diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index b42a4fc117..e54582c299 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -70,13 +70,6 @@ qt_extend_target(Network CONDITION MSVC AND (TEST_architecture_arch STREQUAL "i3 "/BASE:0x64000000" ) -qt_extend_target(Network CONDITION QT_FEATURE_ftp - SOURCES - access/qftp.cpp access/qftp_p.h - access/qnetworkaccessftpbackend.cpp access/qnetworkaccessftpbackend_p.h - kernel/qurlinfo.cpp kernel/qurlinfo_p.h -) - qt_extend_target(Network CONDITION QT_FEATURE_networkdiskcache SOURCES access/qnetworkdiskcache.cpp access/qnetworkdiskcache.h access/qnetworkdiskcache_p.h diff --git a/src/network/access/access.pri b/src/network/access/access.pri index af49fe2bb4..575effb2f0 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -46,16 +46,6 @@ SOURCES += \ access/qhsts.cpp \ access/qhstspolicy.cpp -qtConfig(ftp) { - HEADERS += \ - access/qftp_p.h \ - access/qnetworkaccessftpbackend_p.h - - SOURCES += \ - access/qftp.cpp \ - access/qnetworkaccessftpbackend.cpp -} - qtConfig(networkdiskcache) { HEADERS += \ access/qnetworkdiskcache_p.h \ diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp deleted file mode 100644 index 878f55f604..0000000000 --- a/src/network/access/qftp.cpp +++ /dev/null @@ -1,2456 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -//#define QFTPPI_DEBUG -//#define QFTPDTP_DEBUG - -#include "private/qftp_p.h" -#include "qabstractsocket.h" - -#include "qcoreapplication.h" -#include "qtcpsocket.h" -#include "qurlinfo_p.h" -#include "qstringlist.h" -#include "qregularexpression.h" -#include "qtimer.h" -#include "qfileinfo.h" -#include "qtcpserver.h" -#include "qlocale.h" - -QT_BEGIN_NAMESPACE - -class QFtpPI; - -/* - The QFtpDTP (DTP = Data Transfer Process) controls all client side - data transfer between the client and server. -*/ -class QFtpDTP : public QObject -{ - Q_OBJECT - -public: - enum ConnectState { - CsHostFound, - CsConnected, - CsClosed, - CsHostNotFound, - CsConnectionRefused - }; - - QFtpDTP(QFtpPI *p, QObject *parent = nullptr); - - void setData(QByteArray *); - void setDevice(QIODevice *); - void writeData(); - void setBytesTotal(qint64 bytes); - - bool hasError() const; - QString errorMessage() const; - void clearError(); - - void connectToHost(const QString & host, quint16 port); - int setupListener(const QHostAddress &address); - void waitForConnection(); - - QTcpSocket::SocketState state() const; - qint64 bytesAvailable() const; - qint64 read(char *data, qint64 maxlen); - QByteArray readAll(); - - void abortConnection(); - - static bool parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info); - -signals: - void listInfo(const QUrlInfo&); - void readyRead(); - void dataTransferProgress(qint64, qint64); - - void connectState(int); - -private slots: - void socketConnected(); - void socketReadyRead(); - void socketError(QAbstractSocket::SocketError); - void socketConnectionClosed(); - void socketBytesWritten(qint64); - void setupSocket(); - - void dataReadyRead(); - -private: - void clearData(); - - QTcpSocket *socket; - QTcpServer listener; - - QFtpPI *pi; - QString err; - qint64 bytesDone; - qint64 bytesTotal; - bool callWriteData; - - // If is_ba is true, ba is used; ba is never 0. - // Otherwise dev is used; dev can be 0 or not. - union { - QByteArray *ba; - QIODevice *dev; - } data; - bool is_ba; - - QByteArray bytesFromSocket; -}; - -/********************************************************************** - * - * QFtpPI - Protocol Interpreter - * - *********************************************************************/ - -class QFtpPI : public QObject -{ - Q_OBJECT - -public: - QFtpPI(QObject *parent = nullptr); - - void connectToHost(const QString &host, quint16 port); - - bool sendCommands(const QStringList &cmds); - bool sendCommand(const QString &cmd) - { return sendCommands(QStringList(cmd)); } - - void clearPendingCommands(); - void abort(); - - QString currentCommand() const - { return currentCmd; } - - bool rawCommand; - bool transferConnectionExtended; - - QFtpDTP dtp; // the PI has a DTP which is not the design of RFC 959, but it - // makes the design simpler this way -signals: - void connectState(int); - void finished(const QString&); - void error(int, const QString&); - void rawFtpReply(int, const QString&); - -private slots: - void hostFound(); - void connected(); - void connectionClosed(); - void delayedCloseFinished(); - void readyRead(); - void error(QAbstractSocket::SocketError); - - void dtpConnectState(int); - -private: - // the states are modelled after the generalized state diagram of RFC 959, - // page 58 - enum State { - Begin, - Idle, - Waiting, - Success, - Failure - }; - - enum AbortState { - None, - AbortStarted, - WaitForAbortToFinish - }; - - bool processReply(); - bool startNextCmd(); - - QTcpSocket commandSocket; - QString replyText; - char replyCode[3]; - State state; - AbortState abortState; - QStringList pendingCommands; - QString currentCmd; - - bool waitForDtpToConnect; - bool waitForDtpToClose; - - QByteArray bytesFromSocket; - - friend class QFtpDTP; -}; - -/********************************************************************** - * - * QFtpCommand implemenatation - * - *********************************************************************/ -class QFtpCommand -{ -public: - QFtpCommand(QFtp::Command cmd, const QStringList &raw, const QByteArray &ba); - QFtpCommand(QFtp::Command cmd, const QStringList &raw, QIODevice *dev = nullptr); - ~QFtpCommand(); - - int id; - QFtp::Command command; - QStringList rawCmds; - - // If is_ba is true, ba is used; ba is never 0. - // Otherwise dev is used; dev can be 0 or not. - union { - QByteArray *ba; - QIODevice *dev; - } data; - bool is_ba; - -}; - -static int nextId() -{ - static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0); - return 1 + counter.fetchAndAddRelaxed(1); -} - -QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, const QByteArray &ba) - : command(cmd), rawCmds(raw), is_ba(true) -{ - id = nextId(); - data.ba = new QByteArray(ba); -} - -QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, QIODevice *dev) - : command(cmd), rawCmds(raw), is_ba(false) -{ - id = nextId(); - data.dev = dev; -} - -QFtpCommand::~QFtpCommand() -{ - if (is_ba) - delete data.ba; -} - -/********************************************************************** - * - * QFtpDTP implemenatation - * - *********************************************************************/ -QFtpDTP::QFtpDTP(QFtpPI *p, QObject *parent) : - QObject(parent), - socket(nullptr), - listener(this), - pi(p), - callWriteData(false) -{ - clearData(); - listener.setObjectName(QLatin1String("QFtpDTP active state server")); - connect(&listener, SIGNAL(newConnection()), SLOT(setupSocket())); -} - -void QFtpDTP::setData(QByteArray *ba) -{ - is_ba = true; - data.ba = ba; -} - -void QFtpDTP::setDevice(QIODevice *dev) -{ - is_ba = false; - data.dev = dev; -} - -void QFtpDTP::setBytesTotal(qint64 bytes) -{ - bytesTotal = bytes; - bytesDone = 0; - emit dataTransferProgress(bytesDone, bytesTotal); -} - -void QFtpDTP::connectToHost(const QString & host, quint16 port) -{ - bytesFromSocket.clear(); - - if (socket) { - delete socket; - socket = nullptr; - } - socket = new QTcpSocket(this); - socket->setObjectName(QLatin1String("QFtpDTP Passive state socket")); - connect(socket, SIGNAL(connected()), SLOT(socketConnected())); - connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); - connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); - connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed())); - connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); - - socket->connectToHost(host, port); -} - -int QFtpDTP::setupListener(const QHostAddress &address) -{ - if (!listener.isListening() && !listener.listen(address, 0)) - return -1; - return listener.serverPort(); -} - -void QFtpDTP::waitForConnection() -{ - // This function is only interesting in Active transfer mode; it works - // around a limitation in QFtp's design by blocking, waiting for an - // incoming connection. For the default Passive mode, it does nothing. - if (listener.isListening()) - listener.waitForNewConnection(); -} - -QTcpSocket::SocketState QFtpDTP::state() const -{ - return socket ? socket->state() : QTcpSocket::UnconnectedState; -} - -qint64 QFtpDTP::bytesAvailable() const -{ - if (!socket || socket->state() != QTcpSocket::ConnectedState) - return (qint64) bytesFromSocket.size(); - return socket->bytesAvailable(); -} - -qint64 QFtpDTP::read(char *data, qint64 maxlen) -{ - qint64 read; - if (socket && socket->state() == QTcpSocket::ConnectedState) { - read = socket->read(data, maxlen); - } else { - read = qMin(maxlen, qint64(bytesFromSocket.size())); - memcpy(data, bytesFromSocket.data(), read); - bytesFromSocket.remove(0, read); - } - - bytesDone += read; - return read; -} - -QByteArray QFtpDTP::readAll() -{ - QByteArray tmp; - if (socket && socket->state() == QTcpSocket::ConnectedState) { - tmp = socket->readAll(); - bytesDone += tmp.size(); - } else { - tmp = bytesFromSocket; - bytesFromSocket.clear(); - } - return tmp; -} - -void QFtpDTP::writeData() -{ - if (!socket) - return; - - if (is_ba) { -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::writeData: write %d bytes", data.ba->size()); -#endif - if (data.ba->size() == 0) - emit dataTransferProgress(0, bytesTotal); - else - socket->write(data.ba->data(), data.ba->size()); - - socket->close(); - - clearData(); - } else if (data.dev) { - callWriteData = false; - const qint64 blockSize = 16*1024; - char buf[16*1024]; - qint64 read = data.dev->read(buf, blockSize); -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::writeData: write() of size %lli bytes", read); -#endif - if (read > 0) { - socket->write(buf, read); - } else if (read == -1 || (!data.dev->isSequential() && data.dev->atEnd())) { - // error or EOF - if (bytesDone == 0 && socket->bytesToWrite() == 0) - emit dataTransferProgress(0, bytesTotal); - socket->close(); - clearData(); - } - - // do we continue uploading? - callWriteData = data.dev != nullptr; - } -} - -void QFtpDTP::dataReadyRead() -{ - writeData(); -} - -inline bool QFtpDTP::hasError() const -{ - return !err.isNull(); -} - -inline QString QFtpDTP::errorMessage() const -{ - return err; -} - -inline void QFtpDTP::clearError() -{ - err.clear(); -} - -void QFtpDTP::abortConnection() -{ -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::abortConnection, bytesAvailable == %lli", - socket ? socket->bytesAvailable() : (qint64) 0); -#endif - callWriteData = false; - clearData(); - - if (socket) - socket->abort(); -} - -static void _q_fixupDateTime(QDateTime *dateTime) -{ - // Adjust for future tolerance. - const int futureTolerance = 86400; - if (dateTime->secsTo(QDateTime::currentDateTime()) < -futureTolerance) { - QDate d = dateTime->date(); - d.setDate(d.year() - 1, d.month(), d.day()); - dateTime->setDate(d); - } -} - -static void _q_parseUnixDir(const QStringList &tokens, const QString &userName, QUrlInfo *info) -{ - // Unix style, 7 + 1 entries - // -rw-r--r-- 1 ftp ftp 17358091 Aug 10 2004 qt-x11-free-3.3.3.tar.gz - // drwxr-xr-x 3 ftp ftp 4096 Apr 14 2000 compiled-examples - // lrwxrwxrwx 1 ftp ftp 9 Oct 29 2005 qtscape -> qtmozilla - if (tokens.size() != 8) - return; - - char first = tokens.at(1).at(0).toLatin1(); - if (first == 'd') { - info->setDir(true); - info->setFile(false); - info->setSymLink(false); - } else if (first == '-') { - info->setDir(false); - info->setFile(true); - info->setSymLink(false); - } else if (first == 'l') { - info->setDir(true); - info->setFile(false); - info->setSymLink(true); - } - - // Resolve filename - QString name = tokens.at(7); - if (info->isSymLink()) { - int linkPos = name.indexOf(QLatin1String(" ->")); - if (linkPos != -1) - name.resize(linkPos); - } - info->setName(name); - - // Resolve owner & group - info->setOwner(tokens.at(3)); - info->setGroup(tokens.at(4)); - - // Resolve size - info->setSize(tokens.at(5).toLongLong()); - - QStringList formats; - formats << QLatin1String("MMM dd yyyy") << QLatin1String("MMM dd hh:mm") << QLatin1String("MMM d yyyy") - << QLatin1String("MMM d hh:mm") << QLatin1String("MMM d yyyy") << QLatin1String("MMM dd yyyy"); - - QString dateString = tokens.at(6); - dateString[0] = dateString[0].toUpper(); - - // Resolve the modification date by parsing all possible formats - QDateTime dateTime; - int n = 0; -#if QT_CONFIG(datetimeparser) - do { - dateTime = QLocale::c().toDateTime(dateString, formats.at(n++)); - } while (n < formats.size() && (!dateTime.isValid())); -#endif - - if (n == 2 || n == 4) { - // Guess the year. - dateTime.setDate(QDate(QDate::currentDate().year(), - dateTime.date().month(), - dateTime.date().day())); - _q_fixupDateTime(&dateTime); - } - if (dateTime.isValid()) - info->setLastModified(dateTime); - - // Resolve permissions - int permissions = 0; - const QString &p = tokens.at(2); - permissions |= (p[0] == QLatin1Char('r') ? QUrlInfo::ReadOwner : 0); - permissions |= (p[1] == QLatin1Char('w') ? QUrlInfo::WriteOwner : 0); - permissions |= (p[2] == QLatin1Char('x') ? QUrlInfo::ExeOwner : 0); - permissions |= (p[3] == QLatin1Char('r') ? QUrlInfo::ReadGroup : 0); - permissions |= (p[4] == QLatin1Char('w') ? QUrlInfo::WriteGroup : 0); - permissions |= (p[5] == QLatin1Char('x') ? QUrlInfo::ExeGroup : 0); - permissions |= (p[6] == QLatin1Char('r') ? QUrlInfo::ReadOther : 0); - permissions |= (p[7] == QLatin1Char('w') ? QUrlInfo::WriteOther : 0); - permissions |= (p[8] == QLatin1Char('x') ? QUrlInfo::ExeOther : 0); - info->setPermissions(permissions); - - bool isOwner = info->owner() == userName; - info->setReadable((permissions & QUrlInfo::ReadOther) || ((permissions & QUrlInfo::ReadOwner) && isOwner)); - info->setWritable((permissions & QUrlInfo::WriteOther) || ((permissions & QUrlInfo::WriteOwner) && isOwner)); -} - -static void _q_parseDosDir(const QStringList &tokens, const QString &userName, QUrlInfo *info) -{ - // DOS style, 3 + 1 entries - // 01-16-02 11:14AM epsgroup - // 06-05-03 03:19PM 1973 readme.txt - if (tokens.size() != 4) - return; - - Q_UNUSED(userName); - - QString name = tokens.at(3); - info->setName(name); - info->setSymLink(name.endsWith(QLatin1String(".lnk"), Qt::CaseInsensitive)); - - if (tokens.at(2) == QLatin1String("")) { - info->setFile(false); - info->setDir(true); - } else { - info->setFile(true); - info->setDir(false); - info->setSize(tokens.at(2).toLongLong()); - } - - // Note: We cannot use QFileInfo; permissions are for the server-side - // machine, and QFileInfo's behavior depends on the local platform. - int permissions = QUrlInfo::ReadOwner | QUrlInfo::WriteOwner - | QUrlInfo::ReadGroup | QUrlInfo::WriteGroup - | QUrlInfo::ReadOther | QUrlInfo::WriteOther; - QStringView ext; - int extIndex = name.lastIndexOf(QLatin1Char('.')); - if (extIndex != -1) - ext = QStringView{name}.mid(extIndex + 1); - if (ext == QLatin1String("exe") || ext == QLatin1String("bat") || ext == QLatin1String("com")) - permissions |= QUrlInfo::ExeOwner | QUrlInfo::ExeGroup | QUrlInfo::ExeOther; - info->setPermissions(permissions); - - info->setReadable(true); - info->setWritable(info->isFile()); - - QDateTime dateTime; -#if QT_CONFIG(datetimeparser) - dateTime = QLocale::c().toDateTime(tokens.at(1), QLatin1String("MM-dd-yy hh:mmAP")); - if (dateTime.date().year() < 1971) { - dateTime.setDate(QDate(dateTime.date().year() + 100, - dateTime.date().month(), - dateTime.date().day())); - } -#endif - - info->setLastModified(dateTime); - -} - -bool QFtpDTP::parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info) -{ - if (buffer.isEmpty()) - return false; - - QString bufferStr = QString::fromUtf8(buffer).trimmed(); - - // Unix style FTP servers - QRegularExpression unixPattern(QLatin1String("^([\\-dl])([a-zA-Z\\-]{9,9})\\s+\\d+\\s+(\\S*)\\s+" - "(\\S*)\\s+(\\d+)\\s+(\\S+\\s+\\S+\\s+\\S+)\\s+(\\S.*)")); - auto unixPatternMatch = unixPattern.match(bufferStr); - if (unixPatternMatch.hasMatch()) { - _q_parseUnixDir(unixPatternMatch.capturedTexts(), userName, info); - return true; - } - - // DOS style FTP servers - QRegularExpression dosPattern(QLatin1String("^(\\d\\d-\\d\\d-\\d\\d\\ \\ \\d\\d:\\d\\d[AP]M)\\s+" - "(|\\d+)\\s+(\\S.*)$")); - auto dosPatternMatch = dosPattern.match(bufferStr); - if (dosPatternMatch.hasMatch()) { - _q_parseDosDir(dosPatternMatch.capturedTexts(), userName, info); - return true; - } - - // Unsupported - return false; -} - -void QFtpDTP::socketConnected() -{ - bytesDone = 0; -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::connectState(CsConnected)"); -#endif - emit connectState(QFtpDTP::CsConnected); -} - -void QFtpDTP::socketReadyRead() -{ - if (!socket) - return; - - if (pi->currentCommand().isEmpty()) { - socket->close(); -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::connectState(CsClosed)"); -#endif - emit connectState(QFtpDTP::CsClosed); - return; - } - - if (pi->abortState != QFtpPI::None) { - // discard data - socket->readAll(); - return; - } - - if (pi->currentCommand().startsWith(QLatin1String("LIST"))) { - while (socket->canReadLine()) { - QUrlInfo i; - QByteArray line = socket->readLine(); -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP read (list): '%s'", line.constData()); -#endif - if (parseDir(line, QLatin1String(""), &i)) { - emit listInfo(i); - } else { - // some FTP servers don't return a 550 if the file or directory - // does not exist, but rather write a text to the data socket - // -- try to catch these cases - if (line.endsWith("No such file or directory\r\n")) - err = QString::fromUtf8(line); - } - } - } else { - if (!is_ba && data.dev) { - do { - QByteArray ba; - ba.resize(socket->bytesAvailable()); - qint64 bytesRead = socket->read(ba.data(), ba.size()); - if (bytesRead < 0) { - // a read following a readyRead() signal will - // never fail. - return; - } - ba.resize(bytesRead); - bytesDone += bytesRead; -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP read: %lli bytes (total %lli bytes)", bytesRead, bytesDone); -#endif - if (data.dev) // make sure it wasn't deleted in the slot - data.dev->write(ba); - emit dataTransferProgress(bytesDone, bytesTotal); - - // Need to loop; dataTransferProgress is often connected to - // slots that update the GUI (e.g., progress bar values), and - // if events are processed, more data may have arrived. - } while (socket->bytesAvailable()); - } else { -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP readyRead: %lli bytes available (total %lli bytes read)", - bytesAvailable(), bytesDone); -#endif - emit dataTransferProgress(bytesDone+socket->bytesAvailable(), bytesTotal); - emit readyRead(); - } - } -} - -void QFtpDTP::socketError(QAbstractSocket::SocketError e) -{ - if (e == QTcpSocket::HostNotFoundError) { -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::connectState(CsHostNotFound)"); -#endif - emit connectState(QFtpDTP::CsHostNotFound); - } else if (e == QTcpSocket::ConnectionRefusedError) { -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::connectState(CsConnectionRefused)"); -#endif - emit connectState(QFtpDTP::CsConnectionRefused); - } -} - -void QFtpDTP::socketConnectionClosed() -{ - if (!is_ba && data.dev) { - clearData(); - } - - if (socket->isOpen()) - bytesFromSocket = socket->readAll(); - else - bytesFromSocket.clear(); -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::connectState(CsClosed)"); -#endif - emit connectState(QFtpDTP::CsClosed); -} - -void QFtpDTP::socketBytesWritten(qint64 bytes) -{ - bytesDone += bytes; -#if defined(QFTPDTP_DEBUG) - qDebug("QFtpDTP::bytesWritten(%lli)", bytesDone); -#endif - emit dataTransferProgress(bytesDone, bytesTotal); - if (callWriteData) - writeData(); -} - -void QFtpDTP::setupSocket() -{ - socket = listener.nextPendingConnection(); - socket->setObjectName(QLatin1String("QFtpDTP Active state socket")); - connect(socket, SIGNAL(connected()), SLOT(socketConnected())); - connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); - connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); - connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed())); - connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); - - listener.close(); -} - -void QFtpDTP::clearData() -{ - is_ba = false; - data.dev = nullptr; -} - -/********************************************************************** - * - * QFtpPI implemenatation - * - *********************************************************************/ -QFtpPI::QFtpPI(QObject *parent) : - QObject(parent), - rawCommand(false), - transferConnectionExtended(true), - dtp(this), - commandSocket(nullptr), - state(Begin), abortState(None), - currentCmd(QString()), - waitForDtpToConnect(false), - waitForDtpToClose(false) -{ - commandSocket.setObjectName(QLatin1String("QFtpPI_socket")); - connect(&commandSocket, SIGNAL(hostFound()), - SLOT(hostFound())); - connect(&commandSocket, SIGNAL(connected()), - SLOT(connected())); - connect(&commandSocket, SIGNAL(disconnected()), - SLOT(connectionClosed())); - connect(&commandSocket, SIGNAL(readyRead()), - SLOT(readyRead())); - connect(&commandSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), - SLOT(error(QAbstractSocket::SocketError))); - - connect(&dtp, SIGNAL(connectState(int)), - SLOT(dtpConnectState(int))); -} - -void QFtpPI::connectToHost(const QString &host, quint16 port) -{ - emit connectState(QFtp::HostLookup); - commandSocket.connectToHost(host, port); -} - -/* - \internal - - Sends the sequence of commands \a cmds to the FTP server. When the commands - are all done the finished() signal is emitted. When an error occurs, the - error() signal is emitted. - - If there are pending commands in the queue this functions returns \c false and - the \a cmds are not added to the queue; otherwise it returns \c true. -*/ -bool QFtpPI::sendCommands(const QStringList &cmds) -{ - if (!pendingCommands.isEmpty()) - return false; - - if (commandSocket.state() != QTcpSocket::ConnectedState || state!=Idle) { - emit error(QFtp::NotConnected, QFtp::tr("Not connected")); - return true; // there are no pending commands - } - - pendingCommands = cmds; - startNextCmd(); - return true; -} - -void QFtpPI::clearPendingCommands() -{ - pendingCommands.clear(); - dtp.abortConnection(); - currentCmd.clear(); - state = Idle; -} - -void QFtpPI::abort() -{ - pendingCommands.clear(); - - if (abortState != None) - // ABOR already sent - return; - - if (currentCmd.isEmpty()) - return; //no command in progress - - if (currentCmd.startsWith(QLatin1String("STOR "))) { - abortState = AbortStarted; -#if defined(QFTPPI_DEBUG) - qDebug("QFtpPI send: ABOR"); -#endif - commandSocket.write("ABOR\r\n", 6); - - dtp.abortConnection(); - } else { - //Deviation from RFC 959: - //Most FTP servers do not support ABOR, or require the telnet - //IP & synch sequence (TCP urgent data) which is not supported by QTcpSocket. - //Following what most FTP clients do, just reset the data connection and wait for 426 - abortState = WaitForAbortToFinish; - dtp.abortConnection(); - } -} - -void QFtpPI::hostFound() -{ - emit connectState(QFtp::Connecting); -} - -void QFtpPI::connected() -{ - state = Begin; -#if defined(QFTPPI_DEBUG) -// qDebug("QFtpPI state: %d [connected()]", state); -#endif - // try to improve performance by setting TCP_NODELAY - commandSocket.setSocketOption(QAbstractSocket::LowDelayOption, 1); - - emit connectState(QFtp::Connected); -} - -void QFtpPI::connectionClosed() -{ - commandSocket.close(); - emit connectState(QFtp::Unconnected); -} - -void QFtpPI::delayedCloseFinished() -{ - emit connectState(QFtp::Unconnected); -} - -void QFtpPI::error(QAbstractSocket::SocketError e) -{ - if (e == QTcpSocket::HostNotFoundError) { - emit connectState(QFtp::Unconnected); - emit error(QFtp::HostNotFound, - QFtp::tr("Host %1 not found").arg(commandSocket.peerName())); - } else if (e == QTcpSocket::ConnectionRefusedError) { - emit connectState(QFtp::Unconnected); - emit error(QFtp::ConnectionRefused, - QFtp::tr("Connection refused to host %1").arg(commandSocket.peerName())); - } else if (e == QTcpSocket::SocketTimeoutError) { - emit connectState(QFtp::Unconnected); - emit error(QFtp::ConnectionRefused, - QFtp::tr("Connection timed out to host %1").arg(commandSocket.peerName())); - } -} - -void QFtpPI::readyRead() -{ - if (waitForDtpToClose) - return; - - while (commandSocket.canReadLine()) { - // read line with respect to line continuation - QString line = QString::fromUtf8(commandSocket.readLine()); - if (replyText.isEmpty()) { - if (line.length() < 3) { - // protocol error - return; - } - const int lowerLimit[3] = {1,0,0}; - const int upperLimit[3] = {5,5,9}; - for (int i=0; i<3; i++) { - replyCode[i] = line.at(i).digitValue(); - if (replyCode[i]upperLimit[i]) { - // protocol error - return; - } - } - } - const char count[4] = { char('0' + replyCode[0]), char('0' + replyCode[1]), - char('0' + replyCode[2]), char(' ') }; - QString endOfMultiLine(QLatin1String(count, 4)); - QString lineCont(endOfMultiLine); - lineCont[3] = QLatin1Char('-'); - QStringView lineLeft4 = QStringView{line}.left(4); - - while (lineLeft4 != endOfMultiLine) { - if (lineLeft4 == lineCont) - replyText += QStringView{line}.mid(4); // strip 'xyz-' - else - replyText += line; - if (!commandSocket.canReadLine()) - return; - line = QString::fromUtf8(commandSocket.readLine()); - lineLeft4 = QStringView{line}.left(4); - } - replyText += QStringView{line}.mid(4); // strip reply code 'xyz ' - if (replyText.endsWith(QLatin1String("\r\n"))) - replyText.chop(2); - - if (processReply()) - replyText = QLatin1String(""); - } -} - -/* - \internal - - Process a reply from the FTP server. - - Returns \c true if the reply was processed or false if the reply has to be - processed at a later point. -*/ -bool QFtpPI::processReply() -{ -#if defined(QFTPPI_DEBUG) -// qDebug("QFtpPI state: %d [processReply() begin]", state); - if (replyText.length() < 400) - qDebug("QFtpPI recv: %d %s", 100*replyCode[0]+10*replyCode[1]+replyCode[2], replyText.toLatin1().constData()); - else - qDebug("QFtpPI recv: %d (text skipped)", 100*replyCode[0]+10*replyCode[1]+replyCode[2]); -#endif - - int replyCodeInt = 100*replyCode[0] + 10*replyCode[1] + replyCode[2]; - - // process 226 replies ("Closing Data Connection") only when the data - // connection is really closed to avoid short reads of the DTP - if (replyCodeInt == 226 || (replyCodeInt == 250 && currentCmd.startsWith(QLatin1String("RETR")))) { - if (dtp.state() != QTcpSocket::UnconnectedState) { - waitForDtpToClose = true; - return false; - } - } - - switch (abortState) { - case AbortStarted: - abortState = WaitForAbortToFinish; - break; - case WaitForAbortToFinish: - abortState = None; - return true; - default: - break; - } - - // get new state - static const State table[5] = { - /* 1yz 2yz 3yz 4yz 5yz */ - Waiting, Success, Idle, Failure, Failure - }; - switch (state) { - case Begin: - if (replyCode[0] == 1) { - return true; - } else if (replyCode[0] == 2) { - state = Idle; - emit finished(QFtp::tr("Connected to host %1").arg(commandSocket.peerName())); - break; - } - // reply codes not starting with 1 or 2 are not handled. - return true; - case Waiting: - if (static_cast(replyCode[0]) < 0 || replyCode[0] > 5) - state = Failure; - else - if (replyCodeInt == 202) - state = Failure; - else - state = table[replyCode[0] - 1]; - break; - default: - // ignore unrequested message - return true; - } -#if defined(QFTPPI_DEBUG) -// qDebug("QFtpPI state: %d [processReply() intermediate]", state); -#endif - - // special actions on certain replies - emit rawFtpReply(replyCodeInt, replyText); - if (rawCommand) { - rawCommand = false; - } else if (replyCodeInt == 227) { - // 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2) - // rfc959 does not define this response precisely, and gives - // both examples where the parenthesis are used, and where - // they are missing. We need to scan for the address and host - // info. - QRegularExpression addrPortPattern(QLatin1String("(\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)")); - auto addrPortMatch = addrPortPattern.match(replyText); - if (!addrPortMatch.hasMatch()) { -#if defined(QFTPPI_DEBUG) - qDebug("QFtp: bad 227 response -- address and port information missing"); -#endif - // this error should be reported - } else { - const QStringList lst = addrPortMatch.capturedTexts(); - QString host = lst[1] + QLatin1Char('.') + lst[2] + QLatin1Char('.') + lst[3] + QLatin1Char('.') + lst[4]; - quint16 port = (lst[5].toUInt() << 8) + lst[6].toUInt(); - waitForDtpToConnect = true; - dtp.connectToHost(host, port); - } - } else if (replyCodeInt == 229) { - // 229 Extended Passive mode OK (|||10982|) - int portPos = replyText.indexOf(QLatin1Char('(')); - if (portPos == -1) { -#if defined(QFTPPI_DEBUG) - qDebug("QFtp: bad 229 response -- port information missing"); -#endif - // this error should be reported - } else { - ++portPos; - QChar delimiter = replyText.at(portPos); - const auto epsvParameters = QStringView{replyText}.mid(portPos).split(delimiter); - - waitForDtpToConnect = true; - dtp.connectToHost(commandSocket.peerAddress().toString(), - epsvParameters.at(3).toInt()); - } - - } else if (replyCodeInt == 230) { - if (currentCmd.startsWith(QLatin1String("USER ")) && pendingCommands.count()>0 && - pendingCommands.constFirst().startsWith(QLatin1String("PASS "))) { - // no need to send the PASS -- we are already logged in - pendingCommands.pop_front(); - } - // 230 User logged in, proceed. - emit connectState(QFtp::LoggedIn); - } else if (replyCodeInt == 213) { - // 213 File status. - if (currentCmd.startsWith(QLatin1String("SIZE "))) - dtp.setBytesTotal(replyText.simplified().toLongLong()); - } else if (replyCode[0]==1 && currentCmd.startsWith(QLatin1String("STOR "))) { - dtp.waitForConnection(); - dtp.writeData(); - } - - // react on new state - switch (state) { - case Begin: - // should never happen - break; - case Success: - // success handling - state = Idle; - Q_FALLTHROUGH(); - case Idle: - if (dtp.hasError()) { - emit error(QFtp::UnknownError, dtp.errorMessage()); - dtp.clearError(); - } - startNextCmd(); - break; - case Waiting: - // do nothing - break; - case Failure: - // If the EPSV or EPRT commands fail, replace them with - // the old PASV and PORT instead and try again. - if (currentCmd.startsWith(QLatin1String("EPSV"))) { - transferConnectionExtended = false; - pendingCommands.prepend(QLatin1String("PASV\r\n")); - } else if (currentCmd.startsWith(QLatin1String("EPRT"))) { - transferConnectionExtended = false; - pendingCommands.prepend(QLatin1String("PORT\r\n")); - } else { - emit error(QFtp::UnknownError, replyText); - } - if (state != Waiting) { - state = Idle; - startNextCmd(); - } - break; - } -#if defined(QFTPPI_DEBUG) -// qDebug("QFtpPI state: %d [processReply() end]", state); -#endif - return true; -} - -/* - \internal - - Starts next pending command. Returns \c false if there are no pending commands, - otherwise it returns \c true. -*/ -bool QFtpPI::startNextCmd() -{ - if (waitForDtpToConnect) - // don't process any new commands until we are connected - return true; - -#if defined(QFTPPI_DEBUG) - if (state != Idle) - qDebug("QFtpPI startNextCmd: Internal error! QFtpPI called in non-Idle state %d", state); -#endif - if (pendingCommands.isEmpty()) { - currentCmd.clear(); - emit finished(replyText); - return false; - } - currentCmd = pendingCommands.constFirst(); - - // PORT and PASV are edited in-place, depending on whether we - // should try the extended transfer connection commands EPRT and - // EPSV. The PORT command also triggers setting up a listener, and - // the address/port arguments are edited in. - QHostAddress address = commandSocket.localAddress(); - if (currentCmd.startsWith(QLatin1String("PORT"))) { - if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended) { - int port = dtp.setupListener(address); - currentCmd = QLatin1String("EPRT |"); - currentCmd += (address.protocol() == QTcpSocket::IPv4Protocol) ? QLatin1Char('1') : QLatin1Char('2'); - currentCmd += QLatin1Char('|') + address.toString() + QLatin1Char('|') + QString::number(port); - currentCmd += QLatin1Char('|'); - } else if (address.protocol() == QTcpSocket::IPv4Protocol) { - int port = dtp.setupListener(address); - QString portArg; - quint32 ip = address.toIPv4Address(); - portArg += QString::number((ip & 0xff000000) >> 24); - portArg += QLatin1Char(',') + QString::number((ip & 0xff0000) >> 16); - portArg += QLatin1Char(',') + QString::number((ip & 0xff00) >> 8); - portArg += QLatin1Char(',') + QString::number(ip & 0xff); - portArg += QLatin1Char(',') + QString::number((port & 0xff00) >> 8); - portArg += QLatin1Char(',') + QString::number(port & 0xff); - - currentCmd = QLatin1String("PORT "); - currentCmd += portArg; - } else { - // No IPv6 connection can be set up with the PORT - // command. - return false; - } - - currentCmd += QLatin1String("\r\n"); - } else if (currentCmd.startsWith(QLatin1String("PASV"))) { - if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended) - currentCmd = QLatin1String("EPSV\r\n"); - } - - pendingCommands.pop_front(); -#if defined(QFTPPI_DEBUG) - qDebug("QFtpPI send: %s", QStringView{currentCmd}.left(currentCmd.length() - 2).toLatin1().constData()); -#endif - state = Waiting; - commandSocket.write(currentCmd.toUtf8()); - return true; -} - -void QFtpPI::dtpConnectState(int s) -{ - switch (s) { - case QFtpDTP::CsClosed: - if (waitForDtpToClose) { - // there is an unprocessed reply - if (processReply()) - replyText = QLatin1String(""); - else - return; - } - waitForDtpToClose = false; - readyRead(); - return; - case QFtpDTP::CsConnected: - waitForDtpToConnect = false; - startNextCmd(); - return; - case QFtpDTP::CsHostNotFound: - case QFtpDTP::CsConnectionRefused: - emit error(QFtp::ConnectionRefused, - QFtp::tr("Data Connection refused")); - startNextCmd(); - return; - default: - return; - } -} - -/********************************************************************** - * - * QFtpPrivate - * - *********************************************************************/ - -QT_BEGIN_INCLUDE_NAMESPACE -#include -QT_END_INCLUDE_NAMESPACE - -class QFtpPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QFtp) -public: - - inline QFtpPrivate() : close_waitForStateChange(false), state(QFtp::Unconnected), - transferMode(QFtp::Passive), error(QFtp::NoError) - { } - - ~QFtpPrivate() { while (!pending.isEmpty()) delete pending.takeFirst(); } - - // private slots - void _q_startNextCommand(); - void _q_piFinished(const QString&); - void _q_piError(int, const QString&); - void _q_piConnectState(int); - void _q_piFtpReply(int, const QString&); - - int addCommand(QFtpCommand *cmd); - - QFtpPI pi; - QList pending; - bool close_waitForStateChange; - QFtp::State state; - QFtp::TransferMode transferMode; - QFtp::Error error; - QString errorString; - - QString host; - quint16 port; - QString proxyHost; - quint16 proxyPort; -}; - -int QFtpPrivate::addCommand(QFtpCommand *cmd) -{ - pending.append(cmd); - - if (pending.count() == 1) { - // don't emit the commandStarted() signal before the ID is returned - QTimer::singleShot(0, q_func(), SLOT(_q_startNextCommand())); - } - return cmd->id; -} - -/********************************************************************** - * - * QFtp implementation - * - *********************************************************************/ -/*! - \internal - \class QFtp - \brief The QFtp class provides an implementation of the client side of FTP protocol. - - \ingroup network - \inmodule QtNetwork - - - This class provides a direct interface to FTP that allows you to - have more control over the requests. However, for new - applications, it is recommended to use QNetworkAccessManager and - QNetworkReply, as those classes possess a simpler, yet more - powerful API. - - The class works asynchronously, so there are no blocking - functions. If an operation cannot be executed immediately, the - function will still return straight away and the operation will be - scheduled for later execution. The results of scheduled operations - are reported via signals. This approach depends on the event loop - being in operation. - - The operations that can be scheduled (they are called "commands" - in the rest of the documentation) are the following: - connectToHost(), login(), close(), list(), cd(), get(), put(), - remove(), mkdir(), rmdir(), rename() and rawCommand(). - - All of these commands return a unique identifier that allows you - to keep track of the command that is currently being executed. - When the execution of a command starts, the commandStarted() - signal with the command's identifier is emitted. When the command - is finished, the commandFinished() signal is emitted with the - command's identifier and a bool that indicates whether the command - finished with an error. - - In some cases, you might want to execute a sequence of commands, - e.g. if you want to connect and login to a FTP server. This is - simply achieved: - - \snippet code/src_network_access_qftp.cpp 0 - - In this case two FTP commands have been scheduled. When the last - scheduled command has finished, a done() signal is emitted with - a bool argument that tells you whether the sequence finished with - an error. - - If an error occurs during the execution of one of the commands in - a sequence of commands, all the pending commands (i.e. scheduled, - but not yet executed commands) are cleared and no signals are - emitted for them. - - Some commands, e.g. list(), emit additional signals to report - their results. - - Example: If you want to download the INSTALL file from the Qt - FTP server, you would write this: - - \snippet code/src_network_access_qftp.cpp 1 - - For this example the following sequence of signals is emitted - (with small variations, depending on network traffic, etc.): - - \snippet code/src_network_access_qftp.cpp 2 - - The dataTransferProgress() signal in the above example is useful - if you want to show a \l{QProgressBar}{progress bar} to - inform the user about the progress of the download. The - readyRead() signal tells you that there is data ready to be read. - The amount of data can be queried then with the bytesAvailable() - function and it can be read with the read() or readAll() - function. - - If the login fails for the above example, the signals would look - like this: - - \snippet code/src_network_access_qftp.cpp 3 - - You can then get details about the error with the error() and - errorString() functions. - - For file transfer, QFtp can use both active or passive mode, and - it uses passive file transfer mode by default; see the - documentation for setTransferMode() for more details about this. - - Call setProxy() to make QFtp connect via an FTP proxy server. - - The functions currentId() and currentCommand() provide more - information about the currently executing command. - - The functions hasPendingCommands() and clearPendingCommands() - allow you to query and clear the list of pending commands. - - If you are an experienced network programmer and want to have - complete control you can use rawCommand() to execute arbitrary FTP - commands. - - \warning The current version of QFtp doesn't fully support - non-Unix FTP servers. - - \sa QNetworkAccessManager, QNetworkRequest, QNetworkReply, - {FTP Example} -*/ - - -/*! - \internal - Constructs a QFtp object with the given \a parent. -*/ -QFtp::QFtp(QObject *parent) - : QObject(*new QFtpPrivate, parent) -{ - Q_D(QFtp); - d->errorString = tr("Unknown error"); - - connect(&d->pi, SIGNAL(connectState(int)), - SLOT(_q_piConnectState(int))); - connect(&d->pi, SIGNAL(finished(QString)), - SLOT(_q_piFinished(QString))); - connect(&d->pi, SIGNAL(error(int,QString)), - SLOT(_q_piError(int,QString))); - connect(&d->pi, SIGNAL(rawFtpReply(int,QString)), - SLOT(_q_piFtpReply(int,QString))); - - connect(&d->pi.dtp, SIGNAL(readyRead()), - SIGNAL(readyRead())); - connect(&d->pi.dtp, SIGNAL(dataTransferProgress(qint64,qint64)), - SIGNAL(dataTransferProgress(qint64,qint64))); - connect(&d->pi.dtp, SIGNAL(listInfo(QUrlInfo)), - SIGNAL(listInfo(QUrlInfo))); -} - -/*! - \internal - \enum QFtp::State - - This enum defines the connection state: - - \value Unconnected There is no connection to the host. - \value HostLookup A host name lookup is in progress. - \value Connecting An attempt to connect to the host is in progress. - \value Connected Connection to the host has been achieved. - \value LoggedIn Connection and user login have been achieved. - \value Closing The connection is closing down, but it is not yet - closed. (The state will be \c Unconnected when the connection is - closed.) - - \sa stateChanged(), state() -*/ -/*! - \internal - \enum QFtp::TransferMode - - FTP works with two socket connections; one for commands and - another for transmitting data. While the command connection is - always initiated by the client, the second connection can be - initiated by either the client or the server. - - This enum defines whether the client (Passive mode) or the server - (Active mode) should set up the data connection. - - \value Passive The client connects to the server to transmit its - data. - - \value Active The server connects to the client to transmit its - data. -*/ -/*! - \internal - \enum QFtp::TransferType - - This enum identifies the data transfer type used with get and - put commands. - - \value Binary The data will be transferred in Binary mode. - - \value Ascii The data will be transferred in Ascii mode and new line - characters will be converted to the local format. -*/ -/*! - \internal - \enum QFtp::Error - - This enum identifies the error that occurred. - - \value NoError No error occurred. - \value HostNotFound The host name lookup failed. - \value ConnectionRefused The server refused the connection. - \value NotConnected Tried to send a command, but there is no connection to - a server. - \value UnknownError An error other than those specified above - occurred. - - \sa error() -*/ - -/*! - \internal - \enum QFtp::Command - - This enum is used as the return value for the currentCommand() function. - This allows you to perform specific actions for particular - commands, e.g. in a FTP client, you might want to clear the - directory view when a list() command is started; in this case you - can simply check in the slot connected to the start() signal if - the currentCommand() is \c List. - - \value None No command is being executed. - \value SetTransferMode set the \l{TransferMode}{transfer} mode. - \value SetProxy switch proxying on or off. - \value ConnectToHost connectToHost() is being executed. - \value Login login() is being executed. - \value Close close() is being executed. - \value List list() is being executed. - \value Cd cd() is being executed. - \value Get get() is being executed. - \value Put put() is being executed. - \value Remove remove() is being executed. - \value Mkdir mkdir() is being executed. - \value Rmdir rmdir() is being executed. - \value Rename rename() is being executed. - \value RawCommand rawCommand() is being executed. - - \sa currentCommand() -*/ - -/*! - \internal - \fn void QFtp::stateChanged(int state) - - This signal is emitted when the state of the connection changes. - The argument \a state is the new state of the connection; it is - one of the \l State values. - - It is usually emitted in response to a connectToHost() or close() - command, but it can also be emitted "spontaneously", e.g. when the - server closes the connection unexpectedly. - - \sa connectToHost(), close(), state(), State -*/ - -/*! - \internal - \fn void QFtp::listInfo(const QUrlInfo &i); - - This signal is emitted for each directory entry the list() command - finds. The details of the entry are stored in \a i. - - \sa list() -*/ - -/*! - \internal - \fn void QFtp::commandStarted(int id) - - This signal is emitted when processing the command identified by - \a id starts. - - \sa commandFinished(), done() -*/ - -/*! - \internal - \fn void QFtp::commandFinished(int id, bool error) - - This signal is emitted when processing the command identified by - \a id has finished. \a error is true if an error occurred during - the processing; otherwise \a error is false. - - \sa commandStarted(), done(), error(), errorString() -*/ - -/*! - \internal - \fn void QFtp::done(bool error) - - This signal is emitted when the last pending command has finished; - (it is emitted after the last command's commandFinished() signal). - \a error is true if an error occurred during the processing; - otherwise \a error is false. - - \sa commandFinished(), error(), errorString() -*/ - -/*! - \internal - \fn void QFtp::readyRead() - - This signal is emitted in response to a get() command when there - is new data to read. - - If you specify a device as the second argument in the get() - command, this signal is \e not emitted; instead the data is - written directly to the device. - - You can read the data with the readAll() or read() functions. - - This signal is useful if you want to process the data in chunks as - soon as it becomes available. If you are only interested in the - complete data, just connect to the commandFinished() signal and - read the data then instead. - - \sa get(), read(), readAll(), bytesAvailable() -*/ - -/*! - \internal - \fn void QFtp::dataTransferProgress(qint64 done, qint64 total) - - This signal is emitted in response to a get() or put() request to - indicate the current progress of the download or upload. - - \a done is the amount of data that has already been transferred - and \a total is the total amount of data to be read or written. It - is possible that the QFtp class is not able to determine the total - amount of data that should be transferred, in which case \a total - is 0. (If you connect this signal to a QProgressBar, the progress - bar shows a busy indicator if the total is 0). - - \warning \a done and \a total are not necessarily the size in - bytes, since for large files these values might need to be - "scaled" to avoid overflow. - - \sa get(), put(), QProgressBar -*/ - -/*! - \internal - \fn void QFtp::rawCommandReply(int replyCode, const QString &detail); - - This signal is emitted in response to the rawCommand() function. - \a replyCode is the 3 digit reply code and \a detail is the text - that follows the reply code. - - \sa rawCommand() -*/ - -/*! - \internal - Connects to the FTP server \a host using port \a port. - - The stateChanged() signal is emitted when the state of the - connecting process changes, e.g. to \c HostLookup, then \c - Connecting, then \c Connected. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa stateChanged(), commandStarted(), commandFinished() -*/ -int QFtp::connectToHost(const QString &host, quint16 port) -{ - QStringList cmds; - cmds << host; - cmds << QString::number((uint)port); - int id = d_func()->addCommand(new QFtpCommand(ConnectToHost, cmds)); - d_func()->pi.transferConnectionExtended = true; - return id; -} - -/*! - \internal - Logs in to the FTP server with the username \a user and the - password \a password. - - The stateChanged() signal is emitted when the state of the - connecting process changes, e.g. to \c LoggedIn. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa commandStarted(), commandFinished() -*/ -int QFtp::login(const QString &user, const QString &password) -{ - QStringList cmds; - - if (user.isNull() || user.compare(QLatin1String("anonymous"), Qt::CaseInsensitive) == 0) { - cmds << (QLatin1String("USER ") + (user.isNull() ? QLatin1String("anonymous") : user) + QLatin1String("\r\n")); - cmds << (QLatin1String("PASS ") + (password.isNull() ? QLatin1String("anonymous@") : password) + QLatin1String("\r\n")); - } else { - cmds << (QLatin1String("USER ") + user + QLatin1String("\r\n")); - if (!password.isNull()) - cmds << (QLatin1String("PASS ") + password + QLatin1String("\r\n")); - } - - return d_func()->addCommand(new QFtpCommand(Login, cmds)); -} - -/*! - \internal - Closes the connection to the FTP server. - - The stateChanged() signal is emitted when the state of the - connecting process changes, e.g. to \c Closing, then \c - Unconnected. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa stateChanged(), commandStarted(), commandFinished() -*/ -int QFtp::close() -{ - return d_func()->addCommand(new QFtpCommand(Close, QStringList(QLatin1String("QUIT\r\n")))); -} - -/*! - \internal - Sets the current FTP transfer mode to \a mode. The default is QFtp::Passive. - - \sa QFtp::TransferMode -*/ -int QFtp::setTransferMode(TransferMode mode) -{ - int id = d_func()->addCommand(new QFtpCommand(SetTransferMode, QStringList())); - d_func()->pi.transferConnectionExtended = true; - d_func()->transferMode = mode; - return id; -} - -/*! - \internal - Enables use of the FTP proxy on host \a host and port \a - port. Calling this function with \a host empty disables proxying. - - QFtp does not support FTP-over-HTTP proxy servers. Use - QNetworkAccessManager for this. -*/ -int QFtp::setProxy(const QString &host, quint16 port) -{ - QStringList args; - args << host << QString::number(port); - return d_func()->addCommand(new QFtpCommand(SetProxy, args)); -} - -/*! - \internal - Lists the contents of directory \a dir on the FTP server. If \a - dir is empty, it lists the contents of the current directory. - - The listInfo() signal is emitted for each directory entry found. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa listInfo(), commandStarted(), commandFinished() -*/ -int QFtp::list(const QString &dir) -{ - QStringList cmds; - cmds << QLatin1String("TYPE A\r\n"); - cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); - if (dir.isEmpty()) - cmds << QLatin1String("LIST\r\n"); - else - cmds << (QLatin1String("LIST ") + dir + QLatin1String("\r\n")); - return d_func()->addCommand(new QFtpCommand(List, cmds)); -} - -/*! - \internal - Changes the working directory of the server to \a dir. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa commandStarted(), commandFinished() -*/ -int QFtp::cd(const QString &dir) -{ - return d_func()->addCommand(new QFtpCommand(Cd, QStringList(QLatin1String("CWD ") + dir + QLatin1String("\r\n")))); -} - -/*! - \internal - Downloads the file \a file from the server. - - If \a dev is \nullptr, then the readyRead() signal is emitted when there - is data available to read. You can then read the data with the - read() or readAll() functions. - - If \a dev is not \nullptr, the data is written directly to the device - \a dev. Make sure that the \a dev pointer is valid for the duration - of the operation (it is safe to delete it when the - commandFinished() signal is emitted). In this case the readyRead() - signal is \e not emitted and you cannot read data with the - read() or readAll() functions. - - If you don't read the data immediately it becomes available, i.e. - when the readyRead() signal is emitted, it is still available - until the next command is started. - - For example, if you want to present the data to the user as soon - as there is something available, connect to the readyRead() signal - and read the data immediately. On the other hand, if you only want - to work with the complete data, you can connect to the - commandFinished() signal and read the data when the get() command - is finished. - - The data is transferred as Binary or Ascii depending on the value - of \a type. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa readyRead(), dataTransferProgress(), commandStarted(), - commandFinished() -*/ -int QFtp::get(const QString &file, QIODevice *dev, TransferType type) -{ - QStringList cmds; - if (type == Binary) - cmds << QLatin1String("TYPE I\r\n"); - else - cmds << QLatin1String("TYPE A\r\n"); - cmds << QLatin1String("SIZE ") + file + QLatin1String("\r\n"); - cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); - cmds << QLatin1String("RETR ") + file + QLatin1String("\r\n"); - return d_func()->addCommand(new QFtpCommand(Get, cmds, dev)); -} - -/*! - \internal - \overload - - Writes a copy of the given \a data to the file called \a file on - the server. The progress of the upload is reported by the - dataTransferProgress() signal. - - The data is transferred as Binary or Ascii depending on the value - of \a type. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - Since this function takes a copy of the \a data, you can discard - your own copy when this function returns. - - \sa dataTransferProgress(), commandStarted(), commandFinished() -*/ -int QFtp::put(const QByteArray &data, const QString &file, TransferType type) -{ - QStringList cmds; - if (type == Binary) - cmds << QLatin1String("TYPE I\r\n"); - else - cmds << QLatin1String("TYPE A\r\n"); - cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); - cmds << QLatin1String("ALLO ") + QString::number(data.size()) + QLatin1String("\r\n"); - cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n"); - return d_func()->addCommand(new QFtpCommand(Put, cmds, data)); -} - -/*! - \internal - Reads the data from the IO device \a dev, and writes it to the - file called \a file on the server. The data is read in chunks from - the IO device, so this overload allows you to transmit large - amounts of data without the need to read all the data into memory - at once. - - The data is transferred as Binary or Ascii depending on the value - of \a type. - - Make sure that the \a dev pointer is valid for the duration of the - operation (it is safe to delete it when the commandFinished() is - emitted). -*/ -int QFtp::put(QIODevice *dev, const QString &file, TransferType type) -{ - QStringList cmds; - if (type == Binary) - cmds << QLatin1String("TYPE I\r\n"); - else - cmds << QLatin1String("TYPE A\r\n"); - cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n"); - if (!dev->isSequential()) - cmds << QLatin1String("ALLO ") + QString::number(dev->size()) + QLatin1String("\r\n"); - cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n"); - return d_func()->addCommand(new QFtpCommand(Put, cmds, dev)); -} - -/*! - \internal - Deletes the file called \a file from the server. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa commandStarted(), commandFinished() -*/ -int QFtp::remove(const QString &file) -{ - return d_func()->addCommand(new QFtpCommand(Remove, QStringList(QLatin1String("DELE ") + file + QLatin1String("\r\n")))); -} - -/*! - \internal - Creates a directory called \a dir on the server. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa commandStarted(), commandFinished() -*/ -int QFtp::mkdir(const QString &dir) -{ - return d_func()->addCommand(new QFtpCommand(Mkdir, QStringList(QLatin1String("MKD ") + dir + QLatin1String("\r\n")))); -} - -/*! - \internal - Removes the directory called \a dir from the server. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa commandStarted(), commandFinished() -*/ -int QFtp::rmdir(const QString &dir) -{ - return d_func()->addCommand(new QFtpCommand(Rmdir, QStringList(QLatin1String("RMD ") + dir + QLatin1String("\r\n")))); -} - -/*! - \internal - Renames the file called \a oldname to \a newname on the server. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa commandStarted(), commandFinished() -*/ -int QFtp::rename(const QString &oldname, const QString &newname) -{ - QStringList cmds; - cmds << QLatin1String("RNFR ") + oldname + QLatin1String("\r\n"); - cmds << QLatin1String("RNTO ") + newname + QLatin1String("\r\n"); - return d_func()->addCommand(new QFtpCommand(Rename, cmds)); -} - -/*! - \internal - Sends the raw FTP command \a command to the FTP server. This is - useful for low-level FTP access. If the operation you wish to - perform has an equivalent QFtp function, we recommend using the - function instead of raw FTP commands since the functions are - easier and safer. - - The function does not block and returns immediately. The command - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - commandStarted() and commandFinished(). - - When the command is started the commandStarted() signal is - emitted. When it is finished the commandFinished() signal is - emitted. - - \sa rawCommandReply(), commandStarted(), commandFinished() -*/ -int QFtp::rawCommand(const QString &command) -{ - const QString cmd = QStringView{command}.trimmed() + QLatin1String("\r\n"); - return d_func()->addCommand(new QFtpCommand(RawCommand, QStringList(cmd))); -} - -/*! - \internal - Returns the number of bytes that can be read from the data socket - at the moment. - - \sa get(), readyRead(), read(), readAll() -*/ -qint64 QFtp::bytesAvailable() const -{ - return d_func()->pi.dtp.bytesAvailable(); -} - -/*! - \internal - Reads \a maxlen bytes from the data socket into \a data and - returns the number of bytes read. Returns -1 if an error occurred. - - \sa get(), readyRead(), bytesAvailable(), readAll() -*/ -qint64 QFtp::read(char *data, qint64 maxlen) -{ - return d_func()->pi.dtp.read(data, maxlen); -} - -/*! - \internal - Reads all the bytes available from the data socket and returns - them. - - \sa get(), readyRead(), bytesAvailable(), read() -*/ -QByteArray QFtp::readAll() -{ - return d_func()->pi.dtp.readAll(); -} - -/*! - \internal - Aborts the current command and deletes all scheduled commands. - - If there is an unfinished command (i.e. a command for which the - commandStarted() signal has been emitted, but for which the - commandFinished() signal has not been emitted), this function - sends an \c ABORT command to the server. When the server replies - that the command is aborted, the commandFinished() signal with the - \c error argument set to \c true is emitted for the command. Due - to timing issues, it is possible that the command had already - finished before the abort request reached the server, in which - case, the commandFinished() signal is emitted with the \c error - argument set to \c false. - - For all other commands that are affected by the abort(), no - signals are emitted. - - If you don't start further FTP commands directly after the - abort(), there won't be any scheduled commands and the done() - signal is emitted. - - \warning Some FTP servers, for example the BSD FTP daemon (version - 0.3), wrongly return a positive reply even when an abort has - occurred. For these servers the commandFinished() signal has its - error flag set to \c false, even though the command did not - complete successfully. - - \sa clearPendingCommands() -*/ -void QFtp::abort() -{ - if (d_func()->pending.isEmpty()) - return; - - clearPendingCommands(); - d_func()->pi.abort(); -} - -/*! - \internal - Clears the last error. - - \sa currentCommand() -*/ -void QFtp::clearError() -{ - d_func()->error = NoError; -} - -/*! - \internal - Returns the identifier of the FTP command that is being executed - or 0 if there is no command being executed. - - \sa currentCommand() -*/ -int QFtp::currentId() const -{ - if (d_func()->pending.isEmpty()) - return 0; - return d_func()->pending.first()->id; -} - -/*! - \internal - Returns the command type of the FTP command being executed or \c - None if there is no command being executed. - - \sa currentId() -*/ -QFtp::Command QFtp::currentCommand() const -{ - if (d_func()->pending.isEmpty()) - return None; - return d_func()->pending.first()->command; -} - -/*! - \internal - Returns the QIODevice pointer that is used by the FTP command to read data - from or store data to. If there is no current FTP command being executed or - if the command does not use an IO device, this function returns \nullptr. - - This function can be used to delete the QIODevice in the slot connected to - the commandFinished() signal. - - \sa get(), put() -*/ -QIODevice* QFtp::currentDevice() const -{ - if (d_func()->pending.isEmpty()) - return nullptr; - QFtpCommand *c = d_func()->pending.first(); - if (c->is_ba) - return nullptr; - return c->data.dev; -} - -/*! - \internal - Returns \c true if there are any commands scheduled that have not yet - been executed; otherwise returns \c false. - - The command that is being executed is \e not considered as a - scheduled command. - - \sa clearPendingCommands(), currentId(), currentCommand() -*/ -bool QFtp::hasPendingCommands() const -{ - return d_func()->pending.count() > 1; -} - -/*! - \internal - Deletes all pending commands from the list of scheduled commands. - This does not affect the command that is being executed. If you - want to stop this as well, use abort(). - - \sa hasPendingCommands(), abort() -*/ -void QFtp::clearPendingCommands() -{ - // delete all entires except the first one - while (d_func()->pending.count() > 1) - delete d_func()->pending.takeLast(); -} - -/*! - \internal - Returns the current state of the object. When the state changes, - the stateChanged() signal is emitted. - - \sa State, stateChanged() -*/ -QFtp::State QFtp::state() const -{ - return d_func()->state; -} - -/*! - \internal - Returns the last error that occurred. This is useful to find out - what went wrong when receiving a commandFinished() or a done() - signal with the \c error argument set to \c true. - - If you start a new command, the error status is reset to \c NoError. -*/ -QFtp::Error QFtp::error() const -{ - return d_func()->error; -} - -/*! - \internal - Returns a human-readable description of the last error that - occurred. This is useful for presenting a error message to the - user when receiving a commandFinished() or a done() signal with - the \c error argument set to \c true. - - The error string is often (but not always) the reply from the - server, so it is not always possible to translate the string. If - the message comes from Qt, the string has already passed through - tr(). -*/ -QString QFtp::errorString() const -{ - return d_func()->errorString; -} - -/*! \internal -*/ -void QFtpPrivate::_q_startNextCommand() -{ - Q_Q(QFtp); - if (pending.isEmpty()) - return; - QFtpCommand *c = pending.constFirst(); - - error = QFtp::NoError; - errorString = QT_TRANSLATE_NOOP(QFtp, QLatin1String("Unknown error")); - - if (q->bytesAvailable()) - q->readAll(); // clear the data - emit q->commandStarted(c->id); - - // Proxy support, replace the Login argument in place, then fall - // through. - if (c->command == QFtp::Login && !proxyHost.isEmpty()) { - QString loginString; - loginString += QStringView{c->rawCmds.constFirst()}.trimmed() + QLatin1Char('@') + host; - if (port && port != 21) - loginString += QLatin1Char(':') + QString::number(port); - loginString += QLatin1String("\r\n"); - c->rawCmds[0] = loginString; - } - - if (c->command == QFtp::SetTransferMode) { - _q_piFinished(QLatin1String("Transfer mode set")); - } else if (c->command == QFtp::SetProxy) { - proxyHost = c->rawCmds.at(0); - proxyPort = c->rawCmds.at(1).toUInt(); - c->rawCmds.clear(); - _q_piFinished(QLatin1String("Proxy set to ") + proxyHost + QLatin1Char(':') + QString::number(proxyPort)); - } else if (c->command == QFtp::ConnectToHost) { - if (!proxyHost.isEmpty()) { - host = c->rawCmds.at(0); - port = c->rawCmds.at(1).toUInt(); - pi.connectToHost(proxyHost, proxyPort); - } else { - pi.connectToHost(c->rawCmds.at(0), c->rawCmds.at(1).toUInt()); - } - } else { - if (c->command == QFtp::Put) { - if (c->is_ba) { - pi.dtp.setData(c->data.ba); - pi.dtp.setBytesTotal(c->data.ba->size()); - } else if (c->data.dev && (c->data.dev->isOpen() || c->data.dev->open(QIODevice::ReadOnly))) { - pi.dtp.setDevice(c->data.dev); - if (c->data.dev->isSequential()) { - pi.dtp.setBytesTotal(0); - pi.dtp.connect(c->data.dev, SIGNAL(readyRead()), SLOT(dataReadyRead())); - pi.dtp.connect(c->data.dev, SIGNAL(readChannelFinished()), SLOT(dataReadyRead())); - } else { - pi.dtp.setBytesTotal(c->data.dev->size()); - } - } - } else if (c->command == QFtp::Get) { - if (!c->is_ba && c->data.dev) { - pi.dtp.setDevice(c->data.dev); - } - } else if (c->command == QFtp::Close) { - state = QFtp::Closing; - emit q->stateChanged(state); - } - pi.sendCommands(c->rawCmds); - } -} - -/*! \internal -*/ -void QFtpPrivate::_q_piFinished(const QString&) -{ - if (pending.isEmpty()) - return; - QFtpCommand *c = pending.constFirst(); - - if (c->command == QFtp::Close) { - // The order of in which the slots are called is arbitrary, so - // disconnect the SIGNAL-SIGNAL temporary to make sure that we - // don't get the commandFinished() signal before the stateChanged() - // signal. - if (state != QFtp::Unconnected) { - close_waitForStateChange = true; - return; - } - } - emit q_func()->commandFinished(c->id, false); - pending.removeFirst(); - - delete c; - - if (pending.isEmpty()) { - emit q_func()->done(false); - } else { - _q_startNextCommand(); - } -} - -/*! \internal -*/ -void QFtpPrivate::_q_piError(int errorCode, const QString &text) -{ - Q_Q(QFtp); - - if (pending.isEmpty()) { - qWarning("QFtpPrivate::_q_piError was called without pending command!"); - return; - } - - QFtpCommand *c = pending.constFirst(); - - // non-fatal errors - if (c->command == QFtp::Get && pi.currentCommand().startsWith(QLatin1String("SIZE "))) { - pi.dtp.setBytesTotal(0); - return; - } else if (c->command==QFtp::Put && pi.currentCommand().startsWith(QLatin1String("ALLO "))) { - return; - } - - error = QFtp::Error(errorCode); - switch (q->currentCommand()) { - case QFtp::ConnectToHost: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Connecting to host failed:\n%1")) - .arg(text); - break; - case QFtp::Login: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Login failed:\n%1")) - .arg(text); - break; - case QFtp::List: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Listing directory failed:\n%1")) - .arg(text); - break; - case QFtp::Cd: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Changing directory failed:\n%1")) - .arg(text); - break; - case QFtp::Get: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Downloading file failed:\n%1")) - .arg(text); - break; - case QFtp::Put: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Uploading file failed:\n%1")) - .arg(text); - break; - case QFtp::Remove: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing file failed:\n%1")) - .arg(text); - break; - case QFtp::Mkdir: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Creating directory failed:\n%1")) - .arg(text); - break; - case QFtp::Rmdir: - errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing directory failed:\n%1")) - .arg(text); - break; - default: - errorString = text; - break; - } - - pi.clearPendingCommands(); - q->clearPendingCommands(); - emit q->commandFinished(c->id, true); - - pending.removeFirst(); - delete c; - if (pending.isEmpty()) - emit q->done(true); - else - _q_startNextCommand(); -} - -/*! \internal -*/ -void QFtpPrivate::_q_piConnectState(int connectState) -{ - state = QFtp::State(connectState); - emit q_func()->stateChanged(state); - if (close_waitForStateChange) { - close_waitForStateChange = false; - _q_piFinished(QLatin1String(QT_TRANSLATE_NOOP("QFtp", "Connection closed"))); - } -} - -/*! \internal -*/ -void QFtpPrivate::_q_piFtpReply(int code, const QString &text) -{ - if (q_func()->currentCommand() == QFtp::RawCommand) { - pi.rawCommand = true; - emit q_func()->rawCommandReply(code, text); - } -} - -/*! - \internal - Destructor. -*/ -QFtp::~QFtp() -{ - abort(); - close(); -} - -QT_END_NAMESPACE - -#include "qftp.moc" - -#include "moc_qftp_p.cpp" diff --git a/src/network/access/qftp_p.h b/src/network/access/qftp_p.h deleted file mode 100644 index a55429933b..0000000000 --- a/src/network/access/qftp_p.h +++ /dev/null @@ -1,176 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the Network Access API. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QFTP_P_H -#define QFTP_P_H - -#include -#include -#include -#include - -QT_REQUIRE_CONFIG(ftp); - -QT_BEGIN_NAMESPACE - -class QFtpPrivate; - -class Q_AUTOTEST_EXPORT QFtp : public QObject -{ - Q_OBJECT - -public: - explicit QFtp(QObject *parent = nullptr); - virtual ~QFtp(); - - enum State { - Unconnected, - HostLookup, - Connecting, - Connected, - LoggedIn, - Closing - }; - enum Error { - NoError, - UnknownError, - HostNotFound, - ConnectionRefused, - NotConnected - }; - enum Command { - None, - SetTransferMode, - SetProxy, - ConnectToHost, - Login, - Close, - List, - Cd, - Get, - Put, - Remove, - Mkdir, - Rmdir, - Rename, - RawCommand - }; - enum TransferMode { - Active, - Passive - }; - enum TransferType { - Binary, - Ascii - }; - - int setProxy(const QString &host, quint16 port); - int connectToHost(const QString &host, quint16 port=21); - int login(const QString &user = QString(), const QString &password = QString()); - int close(); - int setTransferMode(TransferMode mode); - int list(const QString &dir = QString()); - int cd(const QString &dir); - int get(const QString &file, QIODevice *dev=nullptr, TransferType type = Binary); - int put(const QByteArray &data, const QString &file, TransferType type = Binary); - int put(QIODevice *dev, const QString &file, TransferType type = Binary); - int remove(const QString &file); - int mkdir(const QString &dir); - int rmdir(const QString &dir); - int rename(const QString &oldname, const QString &newname); - - int rawCommand(const QString &command); - - qint64 bytesAvailable() const; - qint64 read(char *data, qint64 maxlen); - QByteArray readAll(); - - int currentId() const; - QIODevice* currentDevice() const; - Command currentCommand() const; - bool hasPendingCommands() const; - void clearPendingCommands(); - - State state() const; - - Error error() const; - QString errorString() const; - -public Q_SLOTS: - void abort(); - -Q_SIGNALS: - void stateChanged(int); - void listInfo(const QUrlInfo&); - void readyRead(); - void dataTransferProgress(qint64, qint64); - void rawCommandReply(int, const QString&); - - void commandStarted(int); - void commandFinished(int, bool); - void done(bool); - -protected: - void clearError(); - -private: - Q_DISABLE_COPY_MOVE(QFtp) - Q_DECLARE_PRIVATE(QFtp) - - Q_PRIVATE_SLOT(d_func(), void _q_startNextCommand()) - Q_PRIVATE_SLOT(d_func(), void _q_piFinished(const QString&)) - Q_PRIVATE_SLOT(d_func(), void _q_piError(int, const QString&)) - Q_PRIVATE_SLOT(d_func(), void _q_piConnectState(int)) - Q_PRIVATE_SLOT(d_func(), void _q_piFtpReply(int, const QString&)) -}; - -QT_END_NAMESPACE - -#endif // QFTP_P_H diff --git a/src/network/access/qnetworkaccesscachebackend.cpp b/src/network/access/qnetworkaccesscachebackend.cpp index 4986b36ab1..1a4ef27dd6 100644 --- a/src/network/access/qnetworkaccesscachebackend.cpp +++ b/src/network/access/qnetworkaccesscachebackend.cpp @@ -42,9 +42,6 @@ #include "qnetworkaccesscachebackend_p.h" #include "qabstractnetworkcache.h" #include "qfileinfo.h" -#if QT_CONFIG(ftp) -#include "qurlinfo_p.h" -#endif #include "qdir.h" #include "qcoreapplication.h" diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index 507417f86c..046a16162a 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -39,9 +39,6 @@ #include "qnetworkaccessfilebackend_p.h" #include "qfileinfo.h" -#if QT_CONFIG(ftp) -#include "qurlinfo_p.h" -#endif #include "qdir.h" #include "private/qnoncontiguousbytedevice_p.h" diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp deleted file mode 100644 index 7c353b5c47..0000000000 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ /dev/null @@ -1,436 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qnetworkaccessftpbackend_p.h" -#include "qnetworkaccessmanager_p.h" -#include "QtNetwork/qauthenticator.h" -#include "private/qnoncontiguousbytedevice_p.h" -#include - -QT_BEGIN_NAMESPACE - -enum { - DefaultFtpPort = 21 -}; - -static QByteArray makeCacheKey(const QUrl &url) -{ - QUrl copy = url; - copy.setPort(url.port(DefaultFtpPort)); - return "ftp-connection:" + - copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery | - QUrl::RemoveFragment); -} - -QStringList QNetworkAccessFtpBackendFactory::supportedSchemes() const -{ - return QStringList(QStringLiteral("ftp")); -} - -QNetworkAccessBackend * -QNetworkAccessFtpBackendFactory::create(QNetworkAccessManager::Operation op, - const QNetworkRequest &request) const -{ - // is it an operation we know of? - switch (op) { - case QNetworkAccessManager::GetOperation: - case QNetworkAccessManager::PutOperation: - break; - - default: - // no, we can't handle this operation - return nullptr; - } - - QUrl url = request.url(); - if (url.scheme().compare(QLatin1String("ftp"), Qt::CaseInsensitive) == 0) - return new QNetworkAccessFtpBackend; - return nullptr; -} - -class QNetworkAccessCachedFtpConnection: public QFtp, public QNetworkAccessCache::CacheableObject -{ - // Q_OBJECT -public: - QNetworkAccessCachedFtpConnection() - { - setExpires(true); - setShareable(false); - } - - void dispose() override - { - connect(this, SIGNAL(done(bool)), this, SLOT(deleteLater())); - close(); - } - - using QFtp::clearError; -}; - -QNetworkAccessFtpBackend::QNetworkAccessFtpBackend() - : ftp(nullptr), uploadDevice(nullptr), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1), pwdId(-1), - supportsSize(false), supportsMdtm(false), supportsPwd(false), state(Idle) -{ -} - -QNetworkAccessFtpBackend::~QNetworkAccessFtpBackend() -{ - //if backend destroyed while in use, then abort (this is the code path from QNetworkReply::abort) - if (ftp && state != Disconnecting) - ftp->abort(); - disconnectFromFtp(RemoveCachedConnection); -} - -void QNetworkAccessFtpBackend::open() -{ -#ifndef QT_NO_NETWORKPROXY - QNetworkProxy proxy; - const auto proxies = proxyList(); - for (const QNetworkProxy &p : proxies) { - // use the first FTP proxy - // or no proxy at all - if (p.type() == QNetworkProxy::FtpCachingProxy - || p.type() == QNetworkProxy::NoProxy) { - proxy = p; - break; - } - } - - // did we find an FTP proxy or a NoProxy? - if (proxy.type() == QNetworkProxy::DefaultProxy) { - // unsuitable proxies - error(QNetworkReply::ProxyNotFoundError, - tr("No suitable proxy found")); - finished(); - return; - } - -#endif - - QUrl url = this->url(); - if (url.path().isEmpty()) { - url.setPath(QLatin1String("/")); - setUrl(url); - } - if (url.path().endsWith(QLatin1Char('/'))) { - error(QNetworkReply::ContentOperationNotPermittedError, - tr("Cannot open %1: is a directory").arg(url.toString())); - finished(); - return; - } - state = LoggingIn; - - QNetworkAccessCache* objectCache = QNetworkAccessManagerPrivate::getObjectCache(this); - QByteArray cacheKey = makeCacheKey(url); - if (!objectCache->requestEntry(cacheKey, this, - SLOT(ftpConnectionReady(QNetworkAccessCache::CacheableObject*)))) { - ftp = new QNetworkAccessCachedFtpConnection; -#ifndef QT_NO_NETWORKPROXY - if (proxy.type() == QNetworkProxy::FtpCachingProxy) - ftp->setProxy(proxy.hostName(), proxy.port()); -#endif - ftp->connectToHost(url.host(), url.port(DefaultFtpPort)); - ftp->login(url.userName(), url.password()); - - objectCache->addEntry(cacheKey, ftp); - ftpConnectionReady(ftp); - } - - // Put operation - if (operation() == QNetworkAccessManager::PutOperation) { - uploadDevice = QNonContiguousByteDeviceFactory::wrap(createUploadByteDevice()); - uploadDevice->setParent(this); - } -} - -void QNetworkAccessFtpBackend::closeDownstreamChannel() -{ - state = Disconnecting; - if (operation() == QNetworkAccessManager::GetOperation) - ftp->abort(); -} - -void QNetworkAccessFtpBackend::downstreamReadyWrite() -{ - if (state == Transferring && ftp && ftp->bytesAvailable()) - ftpReadyRead(); -} - -void QNetworkAccessFtpBackend::ftpConnectionReady(QNetworkAccessCache::CacheableObject *o) -{ - ftp = static_cast(o); - connect(ftp, SIGNAL(done(bool)), SLOT(ftpDone())); - connect(ftp, SIGNAL(rawCommandReply(int,QString)), SLOT(ftpRawCommandReply(int,QString))); - connect(ftp, SIGNAL(readyRead()), SLOT(ftpReadyRead())); - - // is the login process done already? - if (ftp->state() == QFtp::LoggedIn) - ftpDone(); - - // no, defer the actual operation until after we've logged in -} - -void QNetworkAccessFtpBackend::disconnectFromFtp(CacheCleanupMode mode) -{ - state = Disconnecting; - - if (ftp) { - disconnect(ftp, nullptr, this, nullptr); - - QByteArray key = makeCacheKey(url()); - if (mode == RemoveCachedConnection) { - QNetworkAccessManagerPrivate::getObjectCache(this)->removeEntry(key); - ftp->dispose(); - } else { - QNetworkAccessManagerPrivate::getObjectCache(this)->releaseEntry(key); - } - - ftp = nullptr; - } -} - -void QNetworkAccessFtpBackend::ftpDone() -{ - // the last command we sent is done - if (state == LoggingIn && ftp->state() != QFtp::LoggedIn) { - if (ftp->state() == QFtp::Connected) { - // the login did not succeed - QUrl newUrl = url(); - QString userInfo = newUrl.userInfo(); - newUrl.setUserInfo(QString()); - setUrl(newUrl); - - QAuthenticator auth; - authenticationRequired(&auth); - - if (!auth.isNull()) { - // try again: - newUrl.setUserName(auth.user()); - ftp->login(auth.user(), auth.password()); - return; - } - - // Re insert the user info so that we can remove the cache entry. - newUrl.setUserInfo(userInfo); - setUrl(newUrl); - - error(QNetworkReply::AuthenticationRequiredError, - tr("Logging in to %1 failed: authentication required") - .arg(url().host())); - } else { - // we did not connect - QNetworkReply::NetworkError code; - switch (ftp->error()) { - case QFtp::HostNotFound: - code = QNetworkReply::HostNotFoundError; - break; - - case QFtp::ConnectionRefused: - code = QNetworkReply::ConnectionRefusedError; - break; - - default: - code = QNetworkReply::ProtocolFailure; - break; - } - - error(code, ftp->errorString()); - } - - // we're not connected, so remove the cache entry: - disconnectFromFtp(RemoveCachedConnection); - finished(); - return; - } - - // check for errors: - if (state == CheckingFeatures && ftp->error() == QFtp::UnknownError) { - qWarning("QNetworkAccessFtpBackend: HELP command failed, ignoring it"); - ftp->clearError(); - } else if (ftp->error() != QFtp::NoError) { - QString msg; - if (operation() == QNetworkAccessManager::GetOperation) - msg = tr("Error while downloading %1: %2"); - else - msg = tr("Error while uploading %1: %2"); - msg = msg.arg(url().toString(), ftp->errorString()); - - if (state == Statting) - // file probably doesn't exist - error(QNetworkReply::ContentNotFoundError, msg); - else - error(QNetworkReply::ContentAccessDenied, msg); - - disconnectFromFtp(RemoveCachedConnection); - finished(); - } - - if (state == LoggingIn) { - state = CheckingFeatures; - // send help command to find out if server supports SIZE, MDTM, and PWD - if (operation() == QNetworkAccessManager::GetOperation - || operation() == QNetworkAccessManager::PutOperation) { - helpId = ftp->rawCommand(QLatin1String("HELP")); // get supported commands - } else { - ftpDone(); - } - } else if (state == CheckingFeatures) { - // If a URL path starts with // prefix (/%2F decoded), the resource will - // be retrieved by an absolute path starting with the root directory. - // For the other URLs, the working directory is retrieved by PWD command - // and prepended to the resource path as an absolute path starting with - // the working directory. - state = ResolvingPath; - QString path = url().path(); - if (path.startsWith(QLatin1String("//")) || supportsPwd == false) { - ftpDone(); // no commands sent, move to the next state - } else { - // If a path starts with /~/ prefix, its prefix will be replaced by - // the working directory as an absolute path starting with working - // directory. - if (path.startsWith(QLatin1String("/~/"))) { - // Remove leading /~ symbols - QUrl newUrl = url(); - newUrl.setPath(path.mid(2)); - setUrl(newUrl); - } - - // send PWD command to retrieve the working directory - pwdId = ftp->rawCommand(QLatin1String("PWD")); - } - } else if (state == ResolvingPath) { - state = Statting; - if (operation() == QNetworkAccessManager::GetOperation) { - // logged in successfully, send the stat requests (if supported) - const QString path = url().path(); - if (supportsSize) { - ftp->rawCommand(QLatin1String("TYPE I")); - sizeId = ftp->rawCommand(QLatin1String("SIZE ") + path); // get size - } - if (supportsMdtm) - mdtmId = ftp->rawCommand(QLatin1String("MDTM ") + path); // get modified time - if (!supportsSize && !supportsMdtm) - ftpDone(); // no commands sent, move to the next state - } else { - ftpDone(); - } - } else if (state == Statting) { - // statted successfully, send the actual request - metaDataChanged(); - state = Transferring; - - QFtp::TransferType type = QFtp::Binary; - if (operation() == QNetworkAccessManager::GetOperation) { - setCachingEnabled(true); - ftp->get(url().path(), nullptr, type); - } else { - ftp->put(uploadDevice, url().path(), type); - } - - } else if (state == Transferring) { - // upload or download finished - disconnectFromFtp(); - finished(); - } -} - -void QNetworkAccessFtpBackend::ftpReadyRead() -{ - QByteArray data = ftp->readAll(); - QByteDataBuffer list; - list.append(data); - data.clear(); // important because of implicit sharing! - writeDownstreamData(list); -} - -void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text) -{ - //qDebug() << "FTP reply:" << code << text; - int id = ftp->currentId(); - - if ((id == helpId) && ((code == 200) || (code == 214))) { // supported commands - // the "FEAT" ftp command would be nice here, but it is not part of the - // initial FTP RFC 959, neither ar "SIZE" nor "MDTM" (they are all specified - // in RFC 3659) - if (text.contains(QLatin1String("SIZE"), Qt::CaseSensitive)) - supportsSize = true; - if (text.contains(QLatin1String("MDTM"), Qt::CaseSensitive)) - supportsMdtm = true; - if (text.contains(QLatin1String("PWD"), Qt::CaseSensitive)) - supportsPwd = true; - } else if (id == pwdId && code == 257) { - QString pwdPath; - int startIndex = text.indexOf('"'); - int stopIndex = text.lastIndexOf('"'); - if (stopIndex - startIndex) { - // The working directory is a substring between \" symbols. - startIndex++; // skip the first \" symbol - pwdPath = text.mid(startIndex, stopIndex - startIndex); - } else { - // If there is no or only one \" symbol, use all the characters of - // text. - pwdPath = text; - } - - // If a URL path starts with the working directory prefix, its resource - // will be retrieved from the working directory. Otherwise, the path of - // the working directory is prepended to the resource path. - QString urlPath = url().path(); - if (!urlPath.startsWith(pwdPath)) { - if (pwdPath.endsWith(QLatin1Char('/'))) - pwdPath.chop(1); - // Prepend working directory to the URL path - QUrl newUrl = url(); - newUrl.setPath(pwdPath % urlPath); - setUrl(newUrl); - } - } else if (code == 213) { // file status - if (id == sizeId) { - // reply to the size command - setHeader(QNetworkRequest::ContentLengthHeader, text.toLongLong()); -#if QT_CONFIG(datetimeparser) - } else if (id == mdtmId) { - QDateTime dt = QDateTime::fromString(text, QLatin1String("yyyyMMddHHmmss")); - setHeader(QNetworkRequest::LastModifiedHeader, dt); -#endif - } - } -} - -QT_END_NAMESPACE diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h deleted file mode 100644 index 0b3d35dcd3..0000000000 --- a/src/network/access/qnetworkaccessftpbackend_p.h +++ /dev/null @@ -1,126 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QNETWORKACCESSFTPBACKEND_P_H -#define QNETWORKACCESSFTPBACKEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the Network Access API. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include -#include "qnetworkaccessbackend_p.h" -#include "qnetworkaccesscache_p.h" -#include "qnetworkrequest.h" -#include "qnetworkreply.h" -#include "private/qftp_p.h" - -#include "QtCore/qpointer.h" - -QT_REQUIRE_CONFIG(ftp); - -QT_BEGIN_NAMESPACE - -class QNetworkAccessFtpIODevice; -class QNetworkAccessCachedFtpConnection; - -class QNetworkAccessFtpBackend: public QNetworkAccessBackend -{ - Q_OBJECT -public: - enum State { - Idle, - //Connecting, - LoggingIn, - CheckingFeatures, - ResolvingPath, - Statting, - Transferring, - Disconnecting - }; - - QNetworkAccessFtpBackend(); - virtual ~QNetworkAccessFtpBackend(); - - virtual void open() override; - virtual void closeDownstreamChannel() override; - - virtual void downstreamReadyWrite() override; - - enum CacheCleanupMode { - ReleaseCachedConnection, - RemoveCachedConnection - }; - - void disconnectFromFtp(CacheCleanupMode mode = ReleaseCachedConnection); - -public slots: - void ftpConnectionReady(QNetworkAccessCache::CacheableObject *object); - void ftpDone(); - void ftpReadyRead(); - void ftpRawCommandReply(int code, const QString &text); - -private: - friend class QNetworkAccessFtpIODevice; - QPointer ftp; - QIODevice *uploadDevice; - qint64 totalBytes; - int helpId, sizeId, mdtmId, pwdId; - bool supportsSize, supportsMdtm, supportsPwd; - State state; -}; - -class QNetworkAccessFtpBackendFactory: public QNetworkAccessBackendFactory -{ -public: - virtual QStringList supportedSchemes() const override; - virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, - const QNetworkRequest &request) const override; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index acec69f41f..b56da732e2 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -54,9 +54,6 @@ #include "qhstsstore_p.h" #endif // QT_CONFIG(settings) -#if QT_CONFIG(ftp) -#include "qnetworkaccessftpbackend_p.h" -#endif #include "qnetworkaccessfilebackend_p.h" #include "qnetworkaccessdebugpipebackend_p.h" #include "qnetworkaccesscachebackend_p.h" @@ -94,9 +91,6 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend) -#if QT_CONFIG(ftp) -Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend) -#endif // QT_CONFIG(ftp) #ifdef QT_BUILD_INTERNAL Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend) @@ -159,10 +153,6 @@ bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& static void ensureInitialized() { -#if QT_CONFIG(ftp) - (void) ftpBackend(); -#endif - #ifdef QT_BUILD_INTERNAL (void) debugpipeBackend(); #endif diff --git a/src/network/configure.cmake b/src/network/configure.cmake index 71b2fdf884..e64a98415a 100644 --- a/src/network/configure.cmake +++ b/src/network/configure.cmake @@ -319,14 +319,6 @@ qt_feature_definition("sctp" "QT_NO_SCTP" NEGATE VALUE "1") qt_feature("system-proxies" PRIVATE LABEL "Use system proxies" ) -qt_feature("ftp" PUBLIC - SECTION "Networking" - LABEL "FTP" - PURPOSE "Provides support for the File Transfer Protocol in QNetworkAccessManager." - AUTODETECT OFF - CONDITION QT_FEATURE_textdate AND QT_FEATURE_regularexpression -) -qt_feature_definition("ftp" "QT_NO_FTP" NEGATE VALUE "1") qt_feature("http" PUBLIC SECTION "Networking" LABEL "HTTP" diff --git a/src/network/configure.json b/src/network/configure.json index a8166340dc..ae3af28fec 100644 --- a/src/network/configure.json +++ b/src/network/configure.json @@ -354,14 +354,6 @@ "label": "Use system proxies", "output": [ "privateFeature" ] }, - "ftp": { - "label": "FTP", - "purpose": "Provides support for the File Transfer Protocol in QNetworkAccessManager.", - "section": "Networking", - "autoDetect": false, - "condition": "features.textdate && features.regularexpression", - "output": [ "publicFeature", "feature" ] - }, "http": { "label": "HTTP", "purpose": "Provides support for the Hypertext Transfer Protocol in QNetworkAccessManager.", @@ -498,7 +490,6 @@ For example: "opensslv11", "dtls", "ocsp", - "ftp", "sctp", "system-proxies", "gssapi", diff --git a/src/network/doc/snippets/code/src_network_access_qftp.cpp b/src/network/doc/snippets/code/src_network_access_qftp.cpp deleted file mode 100644 index 8472477a01..0000000000 --- a/src/network/doc/snippets/code/src_network_access_qftp.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -//! [0] -QFtp *ftp = new QFtp(parent); -ftp->connectToHost("ftp.qt-project.org"); -ftp->login(); -//! [0] - - -//! [1] -ftp->connectToHost("ftp.qt-project.org"); // id == 1 -ftp->login(); // id == 2 -ftp->cd("qt"); // id == 3 -ftp->get("INSTALL"); // id == 4 -ftp->close(); // id == 5 -//! [1] - - -//! [2] -start(1) -stateChanged(HostLookup) -stateChanged(Connecting) -stateChanged(Connected) -finished(1, false) - -start(2) -stateChanged(LoggedIn) -finished(2, false) - -start(3) -finished(3, false) - -start(4) -dataTransferProgress(0, 3798) -dataTransferProgress(2896, 3798) -readyRead() -dataTransferProgress(3798, 3798) -readyRead() -finished(4, false) - -start(5) -stateChanged(Closing) -stateChanged(Unconnected) -finished(5, false) - -done(false) -//! [2] - - -//! [3] -start(1) -stateChanged(HostLookup) -stateChanged(Connecting) -stateChanged(Connected) -finished(1, false) - -start(2) -finished(2, true) - -done(true) -//! [3] diff --git a/src/network/doc/src/examples.qdoc b/src/network/doc/src/examples.qdoc index 3d31e04989..8dc598daff 100644 --- a/src/network/doc/src/examples.qdoc +++ b/src/network/doc/src/examples.qdoc @@ -51,7 +51,6 @@ \li \l{network/network-chat}{Network Chat} \li \l{network/fortuneclient}{Fortune Client}\raisedaster \li \l{network/fortuneserver}{Fortune Server}\raisedaster - \li \l{network/qftp}{FTP}\raisedaster \li \l{network/http}{HTTP} \li \l{network/loopback}{Loopback} \li \l{network/threadedfortuneserver}{Threaded Fortune Server}\raisedaster diff --git a/src/network/doc/src/network-programming.qdoc b/src/network/doc/src/network-programming.qdoc index 96bbd8d38b..4f2ebf7c54 100644 --- a/src/network/doc/src/network-programming.qdoc +++ b/src/network/doc/src/network-programming.qdoc @@ -51,7 +51,7 @@ The \l{Qt Network C++ Classes} page contains a list of the C++ classes in Qt Network. - \section1 High Level Network Operations for HTTP and FTP + \section1 High Level Network Operations for HTTP The Network Access API is a collection of classes for performing common network operations. The API provides an abstraction layer @@ -64,7 +64,7 @@ with a request, such as any header information and the encryption used. The URL specified when a request object is constructed determines the protocol used for a request. - Currently HTTP, FTP and local file URLs are supported for uploading + Currently HTTP and local file URLs are supported for uploading and downloading. The coordination of network operations is performed by the diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index c726515d15..cc78555805 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -33,11 +33,6 @@ qtConfig(topleveldomain) { SOURCES += kernel/qtldurl.cpp } -qtConfig(ftp) { - HEADERS += kernel/qurlinfo_p.h - SOURCES += kernel/qurlinfo.cpp -} - qtConfig(dnslookup) { HEADERS += kernel/qdnslookup.h \ kernel/qdnslookup_p.h diff --git a/src/network/kernel/qurlinfo.cpp b/src/network/kernel/qurlinfo.cpp deleted file mode 100644 index e6f2e70ff4..0000000000 --- a/src/network/kernel/qurlinfo.cpp +++ /dev/null @@ -1,727 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qurlinfo_p.h" - -#include "qurl.h" -#include "qdir.h" -#include - -QT_BEGIN_NAMESPACE - -class QUrlInfoPrivate -{ -public: - QUrlInfoPrivate() : - permissions(0), - size(0), - isDir(false), - isFile(true), - isSymLink(false), - isWritable(true), - isReadable(true), - isExecutable(false) - {} - - QString name; - int permissions; - QString owner; - QString group; - qint64 size; - - QDateTime lastModified; - QDateTime lastRead; - bool isDir; - bool isFile; - bool isSymLink; - bool isWritable; - bool isReadable; - bool isExecutable; -}; - - -/*! - \class QUrlInfo - \brief The QUrlInfo class stores information about URLs. - - \internal - \ingroup io - \ingroup network - \inmodule QtNetwork - - The information about a URL that can be retrieved includes name(), - permissions(), owner(), group(), size(), lastModified(), - lastRead(), isDir(), isFile(), isSymLink(), isWritable(), - isReadable() and isExecutable(). - - You can create your own QUrlInfo objects passing in all the - relevant information in the constructor, and you can modify a - QUrlInfo; for each getter mentioned above there is an equivalent - setter. Note that setting values does not affect the underlying - resource that the QUrlInfo provides information about; for example - if you call setWritable(true) on a read-only resource the only - thing changed is the QUrlInfo object, not the resource. - - \sa QUrl, {FTP Example} -*/ - -/*! - \enum QUrlInfo::PermissionSpec - - This enum is used by the permissions() function to report the - permissions of a file. - - \value ReadOwner The file is readable by the owner of the file. - \value WriteOwner The file is writable by the owner of the file. - \value ExeOwner The file is executable by the owner of the file. - \value ReadGroup The file is readable by the group. - \value WriteGroup The file is writable by the group. - \value ExeGroup The file is executable by the group. - \value ReadOther The file is readable by anyone. - \value WriteOther The file is writable by anyone. - \value ExeOther The file is executable by anyone. -*/ - -/*! - Constructs an invalid QUrlInfo object with default values. - - \sa isValid() -*/ - -QUrlInfo::QUrlInfo() -{ - d = nullptr; -} - -/*! - Copy constructor, copies \a ui to this URL info object. -*/ - -QUrlInfo::QUrlInfo(const QUrlInfo &ui) -{ - if (ui.d) { - d = new QUrlInfoPrivate; - *d = *ui.d; - } else { - d = nullptr; - } -} - -/*! - Constructs a QUrlInfo object by specifying all the URL's - information. - - The information that is passed is the \a name, file \a - permissions, \a owner and \a group and the file's \a size. Also - passed is the \a lastModified date/time and the \a lastRead - date/time. Flags are also passed, specifically, \a isDir, \a - isFile, \a isSymLink, \a isWritable, \a isReadable and \a - isExecutable. -*/ - -QUrlInfo::QUrlInfo(const QString &name, int permissions, const QString &owner, - const QString &group, qint64 size, const QDateTime &lastModified, - const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, - bool isWritable, bool isReadable, bool isExecutable) -{ - d = new QUrlInfoPrivate; - d->name = name; - d->permissions = permissions; - d->owner = owner; - d->group = group; - d->size = size; - d->lastModified = lastModified; - d->lastRead = lastRead; - d->isDir = isDir; - d->isFile = isFile; - d->isSymLink = isSymLink; - d->isWritable = isWritable; - d->isReadable = isReadable; - d->isExecutable = isExecutable; -} - - -/*! - Constructs a QUrlInfo object by specifying all the URL's - information. - - The information that is passed is the \a url, file \a - permissions, \a owner and \a group and the file's \a size. Also - passed is the \a lastModified date/time and the \a lastRead - date/time. Flags are also passed, specifically, \a isDir, \a - isFile, \a isSymLink, \a isWritable, \a isReadable and \a - isExecutable. -*/ - -QUrlInfo::QUrlInfo(const QUrl &url, int permissions, const QString &owner, - const QString &group, qint64 size, const QDateTime &lastModified, - const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, - bool isWritable, bool isReadable, bool isExecutable) -{ - d = new QUrlInfoPrivate; - d->name = QFileInfo(url.path()).fileName(); - d->permissions = permissions; - d->owner = owner; - d->group = group; - d->size = size; - d->lastModified = lastModified; - d->lastRead = lastRead; - d->isDir = isDir; - d->isFile = isFile; - d->isSymLink = isSymLink; - d->isWritable = isWritable; - d->isReadable = isReadable; - d->isExecutable = isExecutable; -} - - -/*! - Sets the name of the URL to \a name. The name is the full text, - for example, "http://qt-project.org/doc/qt-5.0/qtcore/qurl.html". - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setName(const QString &name) -{ - if (!d) - d = new QUrlInfoPrivate; - d->name = name; -} - - -/*! - If \a b is true then the URL is set to be a directory; if \a b is - false then the URL is set not to be a directory (which normally - means it is a file). (Note that a URL can refer to both a file and - a directory even though most file systems do not support this.) - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setDir(bool b) -{ - if (!d) - d = new QUrlInfoPrivate; - d->isDir = b; -} - - -/*! - If \a b is true then the URL is set to be a file; if \b is false - then the URL is set not to be a file (which normally means it is a - directory). (Note that a URL can refer to both a file and a - directory even though most file systems do not support this.) - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setFile(bool b) -{ - if (!d) - d = new QUrlInfoPrivate; - d->isFile = b; -} - - -/*! - Specifies that the URL refers to a symbolic link if \a b is true - and that it does not if \a b is false. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setSymLink(bool b) -{ - if (!d) - d = new QUrlInfoPrivate; - d->isSymLink = b; -} - - -/*! - Specifies that the URL is writable if \a b is true and not - writable if \a b is false. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setWritable(bool b) -{ - if (!d) - d = new QUrlInfoPrivate; - d->isWritable = b; -} - - -/*! - Specifies that the URL is readable if \a b is true and not - readable if \a b is false. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setReadable(bool b) -{ - if (!d) - d = new QUrlInfoPrivate; - d->isReadable = b; -} - -/*! - Specifies that the owner of the URL is called \a s. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setOwner(const QString &s) -{ - if (!d) - d = new QUrlInfoPrivate; - d->owner = s; -} - -/*! - Specifies that the owning group of the URL is called \a s. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setGroup(const QString &s) -{ - if (!d) - d = new QUrlInfoPrivate; - d->group = s; -} - -/*! - Specifies the \a size of the URL. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setSize(qint64 size) -{ - if (!d) - d = new QUrlInfoPrivate; - d->size = size; -} - -/*! - Specifies that the URL has access permissions \a p. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setPermissions(int p) -{ - if (!d) - d = new QUrlInfoPrivate; - d->permissions = p; -} - -/*! - Specifies that the object the URL refers to was last modified at - \a dt. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setLastModified(const QDateTime &dt) -{ - if (!d) - d = new QUrlInfoPrivate; - d->lastModified = dt; -} - -/*! - \since 4.4 - - Specifies that the object the URL refers to was last read at - \a dt. - - If you call this function for an invalid URL info, this function - turns it into a valid one. - - \sa isValid() -*/ - -void QUrlInfo::setLastRead(const QDateTime &dt) -{ - if (!d) - d = new QUrlInfoPrivate; - d->lastRead = dt; -} - -/*! - Destroys the URL info object. -*/ - -QUrlInfo::~QUrlInfo() -{ - delete d; -} - -/*! - Assigns the values of \a ui to this QUrlInfo object. -*/ - -QUrlInfo &QUrlInfo::operator=(const QUrlInfo &ui) -{ - if (ui.d) { - if (!d) - d= new QUrlInfoPrivate; - *d = *ui.d; - } else { - delete d; - d = nullptr; - } - return *this; -} - -/*! - Returns the file name of the URL. - - \sa isValid() -*/ - -QString QUrlInfo::name() const -{ - if (!d) - return QString(); - return d->name; -} - -/*! - Returns the permissions of the URL. You can use the \c PermissionSpec flags - to test for certain permissions. - - \sa isValid() -*/ - -int QUrlInfo::permissions() const -{ - if (!d) - return 0; - return d->permissions; -} - -/*! - Returns the owner of the URL. - - \sa isValid() -*/ - -QString QUrlInfo::owner() const -{ - if (!d) - return QString(); - return d->owner; -} - -/*! - Returns the group of the URL. - - \sa isValid() -*/ - -QString QUrlInfo::group() const -{ - if (!d) - return QString(); - return d->group; -} - -/*! - Returns the size of the URL. - - \sa isValid() -*/ - -qint64 QUrlInfo::size() const -{ - if (!d) - return 0; - return d->size; -} - -/*! - Returns the last modification date of the URL. - - \sa isValid() -*/ - -QDateTime QUrlInfo::lastModified() const -{ - if (!d) - return QDateTime(); - return d->lastModified; -} - -/*! - Returns the date when the URL was last read. - - \sa isValid() -*/ - -QDateTime QUrlInfo::lastRead() const -{ - if (!d) - return QDateTime(); - return d->lastRead; -} - -/*! - Returns \c true if the URL is a directory; otherwise returns \c false. - - \sa isValid() -*/ - -bool QUrlInfo::isDir() const -{ - if (!d) - return false; - return d->isDir; -} - -/*! - Returns \c true if the URL is a file; otherwise returns \c false. - - \sa isValid() -*/ - -bool QUrlInfo::isFile() const -{ - if (!d) - return false; - return d->isFile; -} - -/*! - Returns \c true if the URL is a symbolic link; otherwise returns \c false. - - \sa isValid() -*/ - -bool QUrlInfo::isSymLink() const -{ - if (!d) - return false; - return d->isSymLink; -} - -/*! - Returns \c true if the URL is writable; otherwise returns \c false. - - \sa isValid() -*/ - -bool QUrlInfo::isWritable() const -{ - if (!d) - return false; - return d->isWritable; -} - -/*! - Returns \c true if the URL is readable; otherwise returns \c false. - - \sa isValid() -*/ - -bool QUrlInfo::isReadable() const -{ - if (!d) - return false; - return d->isReadable; -} - -/*! - Returns \c true if the URL is executable; otherwise returns \c false. - - \sa isValid() -*/ - -bool QUrlInfo::isExecutable() const -{ - if (!d) - return false; - return d->isExecutable; -} - -/*! - Returns \c true if \a i1 is greater than \a i2; otherwise returns - false. The objects are compared by the value, which is specified - by \a sortBy. This must be one of QDir::Name, QDir::Time or - QDir::Size. -*/ - -bool QUrlInfo::greaterThan(const QUrlInfo &i1, const QUrlInfo &i2, - int sortBy) -{ - switch (sortBy) { - case QDir::Name: - return i1.name() > i2.name(); - case QDir::Time: - return i1.lastModified() > i2.lastModified(); - case QDir::Size: - return i1.size() > i2.size(); - default: - return false; - } -} - -/*! - Returns \c true if \a i1 is less than \a i2; otherwise returns \c false. - The objects are compared by the value, which is specified by \a - sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size. -*/ - -bool QUrlInfo::lessThan(const QUrlInfo &i1, const QUrlInfo &i2, - int sortBy) -{ - return !greaterThan(i1, i2, sortBy); -} - -/*! - Returns \c true if \a i1 equals to \a i2; otherwise returns \c false. - The objects are compared by the value, which is specified by \a - sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size. -*/ - -bool QUrlInfo::equal(const QUrlInfo &i1, const QUrlInfo &i2, - int sortBy) -{ - switch (sortBy) { - case QDir::Name: - return i1.name() == i2.name(); - case QDir::Time: - return i1.lastModified() == i2.lastModified(); - case QDir::Size: - return i1.size() == i2.size(); - default: - return false; - } -} - -/*! - Returns \c true if this QUrlInfo is equal to \a other; otherwise - returns \c false. - - \sa lessThan(), equal() -*/ - -bool QUrlInfo::operator==(const QUrlInfo &other) const -{ - if (!d) - return other.d == nullptr; - if (!other.d) - return false; - - return (d->name == other.d->name && - d->permissions == other.d->permissions && - d->owner == other.d->owner && - d->group == other.d->group && - d->size == other.d->size && - d->lastModified == other.d->lastModified && - d->lastRead == other.d->lastRead && - d->isDir == other.d->isDir && - d->isFile == other.d->isFile && - d->isSymLink == other.d->isSymLink && - d->isWritable == other.d->isWritable && - d->isReadable == other.d->isReadable && - d->isExecutable == other.d->isExecutable); -} - -/*! - \fn bool QUrlInfo::operator!=(const QUrlInfo &other) const - \since 4.2 - - Returns \c true if this QUrlInfo is not equal to \a other; otherwise - returns \c false. - - \sa lessThan(), equal() -*/ - -/*! - Returns \c true if the URL info is valid; otherwise returns \c false. - Valid means that the QUrlInfo contains real information. - - You should always check if the URL info is valid before relying on - the values. -*/ -bool QUrlInfo::isValid() const -{ - return d != nullptr; -} - -QT_END_NAMESPACE diff --git a/src/network/kernel/qurlinfo_p.h b/src/network/kernel/qurlinfo_p.h deleted file mode 100644 index 8180796f49..0000000000 --- a/src/network/kernel/qurlinfo_p.h +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QURLINFO_H -#define QURLINFO_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include - -QT_REQUIRE_CONFIG(ftp); - -QT_BEGIN_NAMESPACE - -class QUrl; -class QUrlInfoPrivate; - -class Q_NETWORK_EXPORT QUrlInfo -{ -public: - enum PermissionSpec { - ReadOwner = 00400, WriteOwner = 00200, ExeOwner = 00100, - ReadGroup = 00040, WriteGroup = 00020, ExeGroup = 00010, - ReadOther = 00004, WriteOther = 00002, ExeOther = 00001 }; - - QUrlInfo(); - QUrlInfo(const QUrlInfo &ui); - QUrlInfo(const QString &name, int permissions, const QString &owner, - const QString &group, qint64 size, const QDateTime &lastModified, - const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, - bool isWritable, bool isReadable, bool isExecutable); - QUrlInfo(const QUrl &url, int permissions, const QString &owner, - const QString &group, qint64 size, const QDateTime &lastModified, - const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink, - bool isWritable, bool isReadable, bool isExecutable); - QUrlInfo &operator=(const QUrlInfo &ui); - virtual ~QUrlInfo(); - - virtual void setName(const QString &name); - virtual void setDir(bool b); - virtual void setFile(bool b); - virtual void setSymLink(bool b); - virtual void setOwner(const QString &s); - virtual void setGroup(const QString &s); - virtual void setSize(qint64 size); - virtual void setWritable(bool b); - virtual void setReadable(bool b); - virtual void setPermissions(int p); - virtual void setLastModified(const QDateTime &dt); - void setLastRead(const QDateTime &dt); - - bool isValid() const; - - QString name() const; - int permissions() const; - QString owner() const; - QString group() const; - qint64 size() const; - QDateTime lastModified() const; - QDateTime lastRead() const; - bool isDir() const; - bool isFile() const; - bool isSymLink() const; - bool isWritable() const; - bool isReadable() const; - bool isExecutable() const; - - static bool greaterThan(const QUrlInfo &i1, const QUrlInfo &i2, - int sortBy); - static bool lessThan(const QUrlInfo &i1, const QUrlInfo &i2, - int sortBy); - static bool equal(const QUrlInfo &i1, const QUrlInfo &i2, - int sortBy); - - bool operator==(const QUrlInfo &i) const; - inline bool operator!=(const QUrlInfo &i) const - { return !operator==(i); } - -private: - QUrlInfoPrivate *d; -}; - -QT_END_NAMESPACE - -#endif // QURLINFO_H diff --git a/tests/auto/network/access/CMakeLists.txt b/tests/auto/network/access/CMakeLists.txt index 1fa4ab6c6e..d225eb1299 100644 --- a/tests/auto/network/access/CMakeLists.txt +++ b/tests/auto/network/access/CMakeLists.txt @@ -16,6 +16,3 @@ if(QT_FEATURE_private_tests) add_subdirectory(hsts) add_subdirectory(qdecompresshelper) endif() -if(QT_FEATURE_ftp AND QT_FEATURE_private_tests) - add_subdirectory(qftp) -endif() diff --git a/tests/auto/network/access/access.pro b/tests/auto/network/access/access.pro index 1cd488baf9..45d7b0cda5 100644 --- a/tests/auto/network/access/access.pro +++ b/tests/auto/network/access/access.pro @@ -24,5 +24,3 @@ SUBDIRS=\ http2 \ hsts \ qdecompresshelper - -qtConfig(ftp): qtConfig(private_tests): SUBDIRS += qftp diff --git a/tests/auto/network/access/qftp/.gitattributes b/tests/auto/network/access/qftp/.gitattributes deleted file mode 100644 index e04709aa2e..0000000000 --- a/tests/auto/network/access/qftp/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -rfc3252.txt -crlf diff --git a/tests/auto/network/access/qftp/.gitignore b/tests/auto/network/access/qftp/.gitignore deleted file mode 100644 index 7a4845df05..0000000000 --- a/tests/auto/network/access/qftp/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -tst_qftp -tst_QFtp_activeMode_inittab diff --git a/tests/auto/network/access/qftp/BLACKLIST b/tests/auto/network/access/qftp/BLACKLIST deleted file mode 100644 index 0a99f3eb00..0000000000 --- a/tests/auto/network/access/qftp/BLACKLIST +++ /dev/null @@ -1,16 +0,0 @@ -# QTBUG-15111 - -[activeMode:WithoutProxy] -redhatenterpriselinuxworkstation-6.6 - -[activeMode:WithoutProxyWithSession] -redhatenterpriselinuxworkstation-6.6 - -[list] -opensuse-leap -windows-7sp1 -windows-10 msvc-2015 -ubuntu -osx -[list:epsvNotSupported] -* diff --git a/tests/auto/network/access/qftp/CMakeLists.txt b/tests/auto/network/access/qftp/CMakeLists.txt deleted file mode 100644 index f67ddd3326..0000000000 --- a/tests/auto/network/access/qftp/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Generated from qftp.pro. - -if(NOT QT_FEATURE_ftp) - return() -endif() -if(NOT QT_FEATURE_private_tests) - return() -endif() - -##################################################################### -## tst_qftp Test: -##################################################################### - -qt_add_test(tst_qftp - SOURCES - tst_qftp.cpp - PUBLIC_LIBRARIES - Qt::Network - Qt::NetworkPrivate -) - -#### Keys ignored in scope 1:.:.:qftp.pro:: -# QT_FOR_CONFIG = "network" -# QT_TEST_SERVER_LIST = "vsftpd" "ftp-proxy" "squid" "danted" -# _REQUIREMENTS = "qtConfig(ftp)" "qtConfig(private_tests)" diff --git a/tests/auto/network/access/qftp/qftp.pro b/tests/auto/network/access/qftp/qftp.pro deleted file mode 100644 index ad610316df..0000000000 --- a/tests/auto/network/access/qftp/qftp.pro +++ /dev/null @@ -1,11 +0,0 @@ -CONFIG += testcase -TARGET = tst_qftp -SOURCES += tst_qftp.cpp -QT_FOR_CONFIG += network - -requires(qtConfig(ftp)) -requires(qtConfig(private_tests)) -QT = core network network-private testlib - -CONFIG += unsupported/testserver -QT_TEST_SERVER_LIST = vsftpd ftp-proxy squid danted diff --git a/tests/auto/network/access/qftp/rfc3252.txt b/tests/auto/network/access/qftp/rfc3252.txt deleted file mode 100644 index b80c61bf0a..0000000000 --- a/tests/auto/network/access/qftp/rfc3252.txt +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - -Network Working Group H. Kennedy -Request for Comments: 3252 Mimezine -Category: Informational 1 April 2002 - - - Binary Lexical Octet Ad-hoc Transport - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document defines a reformulation of IP and two transport layer - protocols (TCP and UDP) as XML applications. - -1. Introduction - -1.1. Overview - - This document describes the Binary Lexical Octet Ad-hoc Transport - (BLOAT): a reformulation of a widely-deployed network-layer protocol - (IP [RFC791]), and two associated transport layer protocols (TCP - [RFC793] and UDP [RFC768]) as XML [XML] applications. It also - describes methods for transporting BLOAT over Ethernet and IEEE 802 - networks as well as encapsulating BLOAT in IP for gatewaying BLOAT - across the public Internet. - -1.2. Motivation - - The wild popularity of XML as a basis for application-level protocols - such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple - Object Access Protocol [SOAP], and Jabber [JABBER] prompted - investigation into the possibility of extending the use of XML in the - protocol stack. Using XML at both the transport and network layer in - addition to the application layer would provide for an amazing amount - of power and flexibility while removing dependencies on proprietary - and hard-to-understand binary protocols. This protocol unification - would also allow applications to use a single XML parser for all - aspects of their operation, eliminating developer time spent figuring - out the intricacies of each new protocol, and moving the hard work of - - - - -Kennedy Informational [Page 1] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - parsing to the XML toolset. The use of XML also mitigates concerns - over "network vs. host" byte ordering which is at the root of many - network application bugs. - -1.3. Relation to Existing Protocols - - The reformulations specified in this RFC follow as closely as - possible the spirit of the RFCs on which they are based, and so MAY - contain elements or attributes that would not be needed in a pure - reworking (e.g. length attributes, which are implicit in XML.) - - The layering of network and transport protocols are maintained in - this RFC despite the optimizations that could be made if the line - were somewhat blurred (i.e. merging TCP and IP into a single, larger - element in the DTD) in order to foster future use of this protocol as - a basis for reformulating other protocols (such as ICMP.) - - Other than the encoding, the behavioral aspects of each of the - existing protocols remain unchanged. Routing, address spaces, TCP - congestion control, etc. behave as specified in the extant standards. - Adapting to new standards and experimental algorithm heuristics for - improving performance will become much easier once the move to BLOAT - has been completed. - -1.4. Requirement Levels - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in BCP 14, RFC 2119 - [RFC2119]. - -2. IPoXML - - This protocol MUST be implemented to be compliant with this RFC. - IPoXML is the root protocol REQUIRED for effective use of TCPoXML - (section 3.) and higher-level application protocols. - - The DTD for this document type can be found in section 7.1. - - The routing of IPoXML can be easily implemented on hosts with an XML - parser, as the regular structure lends itself handily to parsing and - validation of the document/datagram and then processing the - destination address, TTL, and checksum before sending it on to its - next-hop. - - The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the - wider deployment of IPv4 and the fact that implementing IPv6 as XML - would have exceeded the 1500 byte Ethernet MTU. - - - -Kennedy Informational [Page 2] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - All BLOAT implementations MUST use - and specify - the UTF-8 encoding - of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- - formed and include the XMLDecl. - -2.1. IP Description - - A number of items have changed (for the better) from the original IP - specification. Bit-masks, where present have been converted into - human-readable values. IP addresses are listed in their dotted- - decimal notation [RFC1123]. Length and checksum values are present - as decimal integers. - - To calculate the length and checksum fields of the IP element, a - canonicalized form of the element MUST be used. The canonical form - SHALL have no whitespace (including newline characters) between - elements and only one space character between attributes. There - SHALL NOT be a space following the last attribute in an element. - - An iterative method SHOULD be used to calculate checksums, as the - length field will vary based on the size of the checksum. - - The payload element bears special attention. Due to the character - set restrictions of XML, the payload of IP datagrams (which MAY - contain arbitrary data) MUST be encoded for transport. This RFC - REQUIRES the contents of the payload to be encoded in the base-64 - encoding of RFC 2045 [RFC2045], but removes the requirement that the - encoded output MUST be wrapped on 76-character lines. - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 3] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -2.2. Example Datagram - - The following is an example IPoXML datagram with an empty payload: - - - - -
- - - - - - - - - - - - - - - -
- - -
- -3. TCPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.2. - -3.1. TCP Description - - A number of items have changed from the original TCP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - To calculate the length and checksum fields of the TCP element, a - canonicalized form of the element MUST be used as in section 2.1. - - An iterative method SHOULD be used to calculate checksums as in - section 2.1. - - The payload element MUST be encoded as in section 2.1. - - - -Kennedy Informational [Page 4] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - The TCP offset element was expanded to a maximum of 255 from 16 to - allow for the increased size of the header in XML. - - TCPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -3.2. Example Datagram - - The following is an example TCPoXML datagram with an empty payload: - - - - - - - - - - - - - - - - - - - - - - - - -4. UDPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.3. - -4.1. UDP Description - - A number of items have changed from the original UDP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - - - - - - -Kennedy Informational [Page 5] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - To calculate the length and checksum fields of the UDP element, a - canonicalized form of the element MUST be used as in section 2.1. An - iterative method SHOULD be used to calculate checksums as in section - 2.1. - - The payload element MUST be encoded as in section 2.1. - - UDPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -4.2. Example Datagram - - The following is an example UDPoXML datagram with an empty payload: - - - - - - - - - - - - - - -5. Network Transport - - This document provides for the transmission of BLOAT datagrams over - two common families of physical layer transport. Future RFCs will - address additional transports as routing vendors catch up to the - specification, and we begin to see BLOAT routed across the Internet - backbone. - -5.1. Ethernet - - BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the - exception that the type field of the Ethernet frame MUST contain the - value 0xBEEF. The first 5 octets of the Ethernet frame payload will - be 0x3c 3f 78 6d 6c (" - --> - - - - -Kennedy Informational [Page 7] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 9] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 10] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - -7.2. TCPoXML DTD - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 11] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 12] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - -7.3. UDPoXML DTD - - - - - - - - - - - - - - - -Kennedy Informational [Page 13] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -8. Security Considerations - - XML, as a subset of SGML, has the same security considerations as - specified in SGML Media Types [RFC1874]. Security considerations - that apply to IP, TCP and UDP also likely apply to BLOAT as it does - not attempt to correct for issues not related to message format. - -9. References - - [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, - February 2002. (Work in Progress) - - [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, - August 1980. - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, - September 1981. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC894] Hornig, C., "Standard for the Transmission of IP - Datagrams over Ethernet Networks.", RFC 894, April 1984. - - [RFC1042] Postel, J. and J. Reynolds, "Standard for the - Transmission of IP Datagrams Over IEEE 802 Networks", STD - 43, RFC 1042, February 1988. - - [RFC1123] Braden, R., "Requirements for Internet Hosts - - Application and Support", RFC 1123, October 1989. - - [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December - 1995. - - [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, - October 1996. - - [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message - Bodies", RFC 2045, November 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - - - - -Kennedy Informational [Page 14] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", - RFC 3080, March 2001. - - [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., - Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., - "Simple Object Access Protocol (SOAP) 1.1" World Wide Web - Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ - - [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible - Markup Language (XML)" World Wide Web Consortium - Recommendation REC- xml-19980210. - http://www.w3.org/TR/1998/REC-xml-19980210 - -10. Author's Address - - Hugh Kennedy - Mimezine - 1060 West Addison - Chicago, IL 60613 - USA - - EMail: kennedyh@engin.umich.edu - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 15] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -11. Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 16] - diff --git a/tests/auto/network/access/qftp/tst_qftp.cpp b/tests/auto/network/access/qftp/tst_qftp.cpp deleted file mode 100644 index 886a589324..0000000000 --- a/tests/auto/network/access/qftp/tst_qftp.cpp +++ /dev/null @@ -1,2317 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include - -#include -#include -#include -#include "private/qftp_p.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../../network-settings.h" - -template -static QByteArray msgComparison(T1 lhs, const char *op, T2 rhs) -{ - QString result; - QTextStream(&result) << lhs << ' ' << op << ' ' << rhs; - return result.toLatin1(); -} - -class tst_QFtp : public QObject -{ - Q_OBJECT - -public: - tst_QFtp(); - -private slots: - void initTestCase_data(); - void initTestCase(); - void init(); - void cleanup(); - void connectToHost_data(); - void connectToHost(); - void connectToUnresponsiveHost(); - void login_data(); - void login(); - void close_data(); - void close(); - - void list_data(); - void list(); - void cd_data(); - void cd(); - void get_data(); - void get(); - void put_data(); - void put(); - void mkdir_data(); - void mkdir(); - void mkdir2(); - void rename_data(); - void rename(); - - void commandSequence_data(); - void commandSequence(); - - void abort_data(); - void abort(); - - void bytesAvailable_data(); - void bytesAvailable(); - - void activeMode(); - - void proxy_data(); - void proxy(); - - void binaryAscii(); - - void doneSignal(); - void queueMoreCommandsInDoneSlot(); - - void qtbug7359Crash(); - - void loginURL_data(); - void loginURL(); - -protected slots: - void stateChanged( int ); - void listInfo( const QUrlInfo & ); - void readyRead(); - void dataTransferProgress(qint64, qint64); - - void commandStarted( int ); - void commandFinished( int, bool ); - void done( bool ); - void activeModeDone( bool ); - void mkdir2Slot(int id, bool error); - void cdUpSlot(bool); - -private: - QFtp *newFtp(); - void addCommand( QFtp::Command, int ); - bool fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir = QString() ); - bool dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate ); - - void renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile ); - void renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete ); - - QFtp *ftp; - - QList ids; // helper to make sure that all expected signals are emitted - int current_id; - - int connectToHost_state; - int close_state; - int login_state; - int cur_state; - struct CommandResult - { - int id; - int success; - }; - QMap< QFtp::Command, CommandResult > resultMap; - typedef QMap::Iterator ResMapIt; - - int done_success; - int commandSequence_success; - - qlonglong bytesAvailable_finishedGet; - qlonglong bytesAvailable_finished; - qlonglong bytesAvailable_done; - - QList listInfo_i; - QByteArray newData_ba; - qlonglong bytesTotal; - qlonglong bytesDone; - - bool inFileDirExistsFunction; - - QString uniqueExtension; - QString rfc3252File; -}; - -//#define DUMP_SIGNALS - -const int bytesTotal_init = -10; -const int bytesDone_init = -10; - -tst_QFtp::tst_QFtp() : - ftp(0) -{ -} - -void tst_QFtp::initTestCase_data() -{ - QTest::addColumn("setProxy"); - QTest::addColumn("proxyType"); - - QTest::newRow("WithoutProxy") << false << 0; -#if QT_CONFIG(socks5) - QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy); -#endif - //### doesn't work well yet. - //QTest::newRow("WithHttpProxy") << true << int(QNetworkProxy::HttpProxy); -} - -void tst_QFtp::initTestCase() -{ -#if defined(QT_TEST_SERVER) - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21)); - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); -#else - if (!QtNetworkSettings::verifyTestNetworkSettings()) - QSKIP("No network test server available"); -#endif - rfc3252File = QFINDTESTDATA("rfc3252.txt"); - QVERIFY(!rfc3252File.isEmpty()); -} - -void tst_QFtp::init() -{ - QFETCH_GLOBAL(bool, setProxy); - QFETCH_GLOBAL(int, proxyType); - if (setProxy) { -#ifndef QT_NO_NETWORKPROXY - if (proxyType == QNetworkProxy::Socks5Proxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); - } else if (proxyType == QNetworkProxy::HttpProxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128)); - } -#else // !QT_NO_NETWORKPROXY - Q_UNUSED(proxyType); - QSKIP("No proxy support"); -#endif // QT_NO_NETWORKPROXY - } - - delete ftp; - ftp = 0; - - ids.clear(); - current_id = 0; - - resultMap.clear(); - connectToHost_state = -1; - close_state = -1; - login_state = -1; - cur_state = QFtp::Unconnected; - - listInfo_i.clear(); - newData_ba = QByteArray(); - bytesTotal = bytesTotal_init; - bytesDone = bytesDone_init; - - done_success = -1; - commandSequence_success = -1; - - bytesAvailable_finishedGet = 1234567890; - bytesAvailable_finished = 1234567890; - bytesAvailable_done = 1234567890; - - inFileDirExistsFunction = false; - - uniqueExtension = QString::number((quintptr)this) + QString::number(QRandomGenerator::global()->generate()) - + QString::number((qulonglong)time(0)); -} - -void tst_QFtp::cleanup() -{ - if (ftp) { - delete ftp; - ftp = 0; - } - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) { -#ifndef QT_NO_NETWORKPROXY - QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); -#else - QSKIP("No proxy support"); -#endif - } - - delete ftp; - ftp = 0; -} - -void tst_QFtp::connectToHost_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("state"); - - QTest::newRow( "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << (int)QFtp::Connected; - QTest::newRow( "error01" ) << QtNetworkSettings::ftpServerName() << (uint)2222 << (int)QFtp::Unconnected; - QTest::newRow( "error02" ) << QString("foo.bar") << (uint)21 << (int)QFtp::Unconnected; -} - -static QByteArray msgTimedOut(const QString &host, quint16 port = 0) -{ - QByteArray result = "Network operation timed out on " + host.toLatin1(); - if (port) { - result += ':'; - result += QByteArray::number(port); - } - return result; -} - -void tst_QFtp::connectToHost() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - - QTestEventLoop::instance().enterLoop( 61 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - QTEST( connectToHost_state, "state" ); - - ResMapIt it = resultMap.find( QFtp::ConnectToHost ); - QVERIFY( it != resultMap.end() ); - QFETCH( int, state ); - if ( state == QFtp::Connected ) { - QCOMPARE( it.value().success, 1 ); - } else { - QCOMPARE( it.value().success , 0 ); - } -} - -void tst_QFtp::connectToUnresponsiveHost() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - QSKIP( "This test takes too long if we test with proxies too"); - - QString host = "192.0.2.42"; // IP out of TEST-NET, should be unreachable - uint port = 21; - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - - qDebug( "About to connect to host that won't reply (this test takes 60 seconds)" ); - QTestEventLoop::instance().enterLoop( 61 ); -#ifdef Q_OS_WIN - /* On Windows, we do not get a timeout, because Winsock is behaving in a strange way: - We issue two "WSAConnect()" calls, after the first, as a result we get WSAEWOULDBLOCK, - after the second, we get WSAEISCONN, which means that the socket is connected, which cannot be. - However, after some seconds we get a socket error saying that the remote host closed the connection, - which can neither be. For this test, that would actually enable us to finish before timout, but handling that case - (in void QFtpPI::error(QAbstractSocket::SocketError e)) breaks - a lot of other stuff in QFtp, so we just expect this test to fail on Windows. - */ - QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort); - -#endif - QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)"); - - QCOMPARE( ftp->state(), QFtp::Unconnected); - ResMapIt it = resultMap.find( QFtp::ConnectToHost ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 0 ); - - delete ftp; - ftp = 0; -} - -void tst_QFtp::login_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("success"); - - QTest::newRow( "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << 1; - QTest::newRow( "ok02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("") << 1; - QTest::newRow( "ok03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << 1; - QTest::newRow( "ok04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << 1; - - QTest::newRow( "error01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("") << 0; - QTest::newRow( "error02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("bar") << 0; -} - -void tst_QFtp::login() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - ResMapIt it = resultMap.find( QFtp::Login ); - QVERIFY( it != resultMap.end() ); - QTEST( it.value().success, "success" ); - - const QFtp::State loginState = static_cast(login_state); - if ( it.value().success ) { - QCOMPARE( loginState, QFtp::LoggedIn ); - } else { - QVERIFY2( loginState != QFtp::LoggedIn, msgComparison(loginState, "!=", QFtp::LoggedIn)); - } -} - -void tst_QFtp::close_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("login"); - - QTest::newRow( "login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << true; - QTest::newRow( "login02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString() << true; - QTest::newRow( "login03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << true; - QTest::newRow( "login04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << true; - - QTest::newRow( "no-login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("") << QString("") << false; -} - -void tst_QFtp::close() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( bool, login ); - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - if ( login ) - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - QCOMPARE( close_state, (int)QFtp::Unconnected ); - - ResMapIt it = resultMap.find( QFtp::Close ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 1 ); -} - -void tst_QFtp::list_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("dir"); - QTest::addColumn("success"); - QTest::addColumn("entryNames"); // ### we should rather use a QList here - - QStringList flukeRoot; - flukeRoot << "pub"; - flukeRoot << "qtest"; - QStringList flukeQtest; - flukeQtest << "bigfile"; - flukeQtest << "nonASCII"; - flukeQtest << "rfc3252"; - flukeQtest << "rfc3252.txt"; - flukeQtest << "upload"; - - QTest::newRow( "workDir01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString() << 1 << flukeRoot; - QTest::newRow( "workDir02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString() << 1 << flukeRoot; - - QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; - - QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; - QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; - - QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 1 << QStringList(); - QTest::newRow( "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 1 << QStringList(); - // ### The microsoft server does not seem to work properly at the moment -- - // I am also not able to open a data connection with other, non-Qt FTP - // clients to it. - // QTest::newRow( "nonExist03" ) << "ftp.microsoft.com" << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); - - QStringList susePub; - susePub << "README.mirror-policy" << "axp" << "i386" << "ia64" << "install" << "noarch" << "pubring.gpg-build.suse.de" << "update" << "x86_64"; - QTest::newRow( "epsvNotSupported" ) << QString("ftp.funet.fi") << (uint)21 << QString::fromLatin1("ftp") << QString::fromLatin1("root@") << QString("/pub/Linux/suse/suse") << 1 << susePub; -} - -void tst_QFtp::list() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( QString, dir ); - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::List, ftp->list( dir ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - ResMapIt it = resultMap.find( QFtp::List ); - QVERIFY( it != resultMap.end() ); - QTEST( it.value().success, "success" ); - QFETCH( QStringList, entryNames ); - QCOMPARE( listInfo_i.count(), entryNames.count() ); - for ( uint i=0; i < (uint) entryNames.count(); i++ ) { - QCOMPARE( listInfo_i[i].name(), entryNames[i] ); - } -} - -void tst_QFtp::cd_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("dir"); - QTest::addColumn("success"); - QTest::addColumn("entryNames"); // ### we should rather use a QList here - - QStringList flukeRoot; - flukeRoot << "qtest"; - QStringList flukeQtest; - flukeQtest << "bigfile"; - flukeQtest << "nonASCII"; - flukeQtest << "rfc3252"; - flukeQtest << "rfc3252.txt"; - flukeQtest << "upload"; - - QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; - - QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; - QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; - - QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); - QTest::newRow( "nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); -} - -void tst_QFtp::cd() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( QString, dir ); - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Cd, ftp->cd( dir ) ); - addCommand( QFtp::List, ftp->list() ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) { - QFAIL( msgTimedOut(host, port) ); - } - - ResMapIt it = resultMap.find( QFtp::Cd ); - QVERIFY( it != resultMap.end() ); - QTEST( it.value().success, "success" ); - QFETCH( QStringList, entryNames ); - QCOMPARE( listInfo_i.count(), entryNames.count() ); - for ( uint i=0; i < (uint) entryNames.count(); i++ ) { - QCOMPARE( listInfo_i[i].name(), entryNames[i] ); - } -} - -void tst_QFtp::get_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("file"); - QTest::addColumn("success"); - QTest::addColumn("res"); - QTest::addColumn("useIODevice"); - - // ### move this into external testdata - QFile file(rfc3252File); - QVERIFY2( file.open( QIODevice::ReadOnly ), qPrintable(file.errorString()) ); - QByteArray rfc3252 = file.readAll(); - - // test the two get() overloads in one routine - for ( int i=0; i<2; i++ ) { - const QByteArray iB = QByteArray::number(i); - QTest::newRow(("relPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - QTest::newRow(("relPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - - QTest::newRow(("absPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << "/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - QTest::newRow(("absPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << "/var/ftp/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); - - QTest::newRow(("nonExist01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << QString("foo") << 0 << QByteArray() << (bool)(i==1); - QTest::newRow(("nonExist02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << QString("/foo") << 0 << QByteArray() << (bool)(i==1); - } -} - -void tst_QFtp::get() -{ - // for the overload that takes a QIODevice - QByteArray buf_ba; - QBuffer buf( &buf_ba ); - - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( QString, file ); - QFETCH( bool, useIODevice ); - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - if ( useIODevice ) { - buf.open( QIODevice::WriteOnly ); - addCommand( QFtp::Get, ftp->get( file, &buf ) ); - } else { - addCommand( QFtp::Get, ftp->get( file ) ); - } - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 50 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - ResMapIt it = resultMap.find( QFtp::Get ); - QVERIFY( it != resultMap.end() ); - QTEST( it.value().success, "success" ); - if ( useIODevice ) { - QTEST( buf_ba, "res" ); - } else { - QTEST( newData_ba, "res" ); - } - QVERIFY2( bytesTotal != bytesTotal_init, msgComparison(bytesTotal, "!=", bytesTotal_init) ); - if ( bytesTotal != -1 ) { - QCOMPARE( bytesDone, bytesTotal ); - } - if ( useIODevice ) { - if ( bytesDone != bytesDone_init ) { - QCOMPARE( qlonglong(buf_ba.size()), bytesDone ); - } - } else { - if ( bytesDone != bytesDone_init ) { - QCOMPARE( qlonglong(newData_ba.size()), bytesDone ); - } - } -} - -void tst_QFtp::put_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("file"); - QTest::addColumn("fileData"); - QTest::addColumn("useIODevice"); - QTest::addColumn("success"); - - // ### move this into external testdata - QFile file(rfc3252File); - QVERIFY2( file.open( QIODevice::ReadOnly ), qPrintable(file.errorString()) ); - QByteArray rfc3252 = file.readAll(); - - QByteArray bigData( 10*1024*1024, 0 ); - bigData.fill( 'A' ); - - // test the two put() overloads in one routine with a file name containing - // U+0x00FC (latin small letter u with diaeresis) for QTBUG-52303, testing UTF-8 - for ( int i=0; i<2; i++ ) { - QTest::newRow(("relPath01_" + QByteArray::number(i)).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << (QLatin1String("qtest/upload/rel01_") + QChar(0xfc) + QLatin1String("%1")) << rfc3252 - << (bool)(i==1) << 1; - /* - QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << QString("qtest/upload/rel02_%1") << rfc3252 - << (bool)(i==1) << 1; - QTest::newRow( QString("relPath03_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << QString("qtest/upload/rel03_%1") << QByteArray() - << (bool)(i==1) << 1; - QTest::newRow( QString("relPath04_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << QString("qtest/upload/rel04_%1") << bigData - << (bool)(i==1) << 1; - - QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << QString("/qtest/upload/abs01_%1") << rfc3252 - << (bool)(i==1) << 1; - QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << QString("/srv/ftp/qtest/upload/abs02_%1") << rfc3252 - << (bool)(i==1) << 1; - - QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << QString("foo") << QByteArray() - << (bool)(i==1) << 0; - QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << QString("/foo") << QByteArray() - << (bool)(i==1) << 0; -*/ - } -} - -void tst_QFtp::put() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( QString, file ); - QFETCH( QByteArray, fileData ); - QFETCH( bool, useIODevice ); - -#if defined(Q_OS_WIN) && !defined(QT_NO_NETWORKPROXY) - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) { - QFETCH_GLOBAL(int, proxyType); - if (proxyType == QNetworkProxy::Socks5Proxy) - QSKIP("With socks5 the put() test takes too long time on Windows."); - } -#endif // OS_WIN && !QT_NO_NETWORKPROXY - - const int timestep = 50; - - if(file.contains('%')) - file = file.arg(uniqueExtension); - - // for the overload that takes a QIODevice - QBuffer buf_fileData( &fileData ); - buf_fileData.open( QIODevice::ReadOnly ); - - ResMapIt it; - ////////////////////////////////////////////////////////////////// - // upload the file - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - if ( useIODevice ) - addCommand( QFtp::Put, ftp->put( &buf_fileData, file ) ); - else - addCommand( QFtp::Put, ftp->put( fileData, file ) ); - addCommand( QFtp::Close, ftp->close() ); - - for(int time = 0; time <= fileData.length() / 20000; time += timestep) { - QTestEventLoop::instance().enterLoop( timestep ); - if(ftp->currentCommand() == QFtp::None) - break; - } - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - it = resultMap.find( QFtp::Put ); - QVERIFY( it != resultMap.end() ); - QTEST( it.value().success, "success" ); - if ( !it.value().success ) { - QVERIFY( !fileExists( host, port, user, password, file ) ); - return; // the following tests are only meaningful if the file could be put - } - QCOMPARE( bytesTotal, qlonglong(fileData.size()) ); - QCOMPARE( bytesDone, bytesTotal ); - - QVERIFY( fileExists( host, port, user, password, file ) ); - - ////////////////////////////////////////////////////////////////// - // fetch file to make sure that it is equal to the uploaded file - init(); - ftp = newFtp(); - QBuffer buf; - buf.open( QIODevice::WriteOnly ); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Get, ftp->get( file, &buf ) ); - addCommand( QFtp::Close, ftp->close() ); - - for(int time = 0; time <= fileData.length() / 20000; time += timestep) { - QTestEventLoop::instance().enterLoop( timestep ); - if(ftp->currentCommand() == QFtp::None) - break; - } - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - QCOMPARE( done_success, 1 ); - QTEST( buf.buffer(), "fileData" ); - - ////////////////////////////////////////////////////////////////// - // cleanup (i.e. remove the file) -- this also tests the remove command - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Remove, ftp->remove( file ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( timestep ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - it = resultMap.find( QFtp::Remove ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 1 ); - - QVERIFY( !fileExists( host, port, user, password, file ) ); -} - -void tst_QFtp::mkdir_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("cdDir"); - QTest::addColumn("dirToCreate"); - QTest::addColumn("success"); - - QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << "qtest/upload" << QString("rel01_%1") << 1; - QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << "qtest/upload" << QString("rel02_%1") << 1; - QTest::newRow( "relPath03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << "qtest/upload" << QString("rel03_%1") << 1; - - QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << "." << QString("/qtest/upload/abs01_%1") << 1; - QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") - << "." << QString("/var/ftp/qtest/upload/abs02_%1") << 1; - - // QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0; - QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << "." << QString("foo") << 0; - QTest::newRow( "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() - << "." << QString("/foo") << 0; -} - -void tst_QFtp::mkdir() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( QString, cdDir ); - QFETCH( QString, dirToCreate ); - - if(dirToCreate.contains('%')) - dirToCreate = dirToCreate.arg(uniqueExtension); - - ////////////////////////////////////////////////////////////////// - // create the directory - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Cd, ftp->cd( cdDir ) ); - addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - ResMapIt it = resultMap.find( QFtp::Mkdir ); - QVERIFY( it != resultMap.end() ); - QTEST( it.value().success, "success" ); - if ( !it.value().success ) { - QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) ); - return; // the following tests are only meaningful if the dir could be created - } - QVERIFY( dirExists( host, port, user, password, cdDir, dirToCreate ) ); - - ////////////////////////////////////////////////////////////////// - // create the directory again (should always fail!) - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Cd, ftp->cd( cdDir ) ); - addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - it = resultMap.find( QFtp::Mkdir ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 0 ); - - ////////////////////////////////////////////////////////////////// - // remove the directory - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Cd, ftp->cd( cdDir ) ); - addCommand( QFtp::Rmdir, ftp->rmdir( dirToCreate ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - it = resultMap.find( QFtp::Rmdir ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 1 ); - - QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) ); -} - -void tst_QFtp::mkdir2() -{ - ftp = new QFtp; - ftp->connectToHost(QtNetworkSettings::ftpServerName()); - ftp->login(); - current_id = ftp->cd("kake/test"); - - QEventLoop loop; - connect(ftp, SIGNAL(done(bool)), &loop, SLOT(quit())); - connect(ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(mkdir2Slot(int,bool))); - QTimer::singleShot(5000, &loop, SLOT(quit())); - - QSignalSpy commandStartedSpy(ftp, SIGNAL(commandStarted(int))); - QSignalSpy commandFinishedSpy(ftp, SIGNAL(commandFinished(int,bool))); - - loop.exec(); - - QCOMPARE(commandStartedSpy.count(), 4); // connect, login, cd, mkdir - QCOMPARE(commandFinishedSpy.count(), 4); - - for (int i = 0; i < 4; ++i) - QCOMPARE(commandFinishedSpy.at(i).at(0), commandStartedSpy.at(i).at(0)); - - QVERIFY(!commandFinishedSpy.at(0).at(1).toBool()); - QVERIFY(!commandFinishedSpy.at(1).at(1).toBool()); - QVERIFY(commandFinishedSpy.at(2).at(1).toBool()); - QVERIFY(commandFinishedSpy.at(3).at(1).toBool()); - - delete ftp; - ftp = 0; -} - -void tst_QFtp::mkdir2Slot(int id, bool) -{ - if (id == current_id) - ftp->mkdir("kake/test"); -} - -void tst_QFtp::rename_data() -{ - QTest::addColumn("host"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("cdDir"); - QTest::addColumn("oldfile"); - QTest::addColumn("newfile"); - QTest::addColumn("createFile"); - QTest::addColumn("renamedFile"); - QTest::addColumn("success"); - - QTest::newRow("relPath01") << QtNetworkSettings::ftpServerName() << QString() << QString() - << "qtest/upload" - << QString("rel_old01_%1") << QString("rel_new01_%1") - << QString("qtest/upload/rel_old01_%1") << QString("qtest/upload/rel_new01_%1") - << 1; - QTest::newRow("relPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password" - << "qtest/upload" - << QString("rel_old02_%1") << QString("rel_new02_%1") - << QString("qtest/upload/rel_old02_%1") << QString("qtest/upload/rel_new02_%1") - << 1; - QTest::newRow("relPath03") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password" - << "qtest/upload" - << QString("rel_old03_%1")<< QString("rel_new03_%1") - << QString("qtest/upload/rel_old03_%1") << QString("qtest/upload/rel_new03_%1") - << 1; - - QTest::newRow("absPath01") << QtNetworkSettings::ftpServerName() << QString() << QString() - << QString() - << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1") - << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1") - << 1; - QTest::newRow("absPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password" - << QString() - << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1") - << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1") - << 1; - - QTest::newRow("nonExist01") << QtNetworkSettings::ftpServerName() << QString() << QString() - << QString() - << QString("foo") << "new_foo" - << QString() << QString() - << 0; - QTest::newRow("nonExist02") << QtNetworkSettings::ftpServerName() << QString() << QString() - << QString() - << QString("/foo") << QString("/new_foo") - << QString() << QString() - << 0; -} - -void tst_QFtp::renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile ) -{ - if ( !createFile.isNull() ) { - // upload the file - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Put, ftp->put( QByteArray(), createFile ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 50 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host) ); - - ResMapIt it = resultMap.find( QFtp::Put ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 1 ); - - QVERIFY( fileExists( host, 21, user, password, createFile ) ); - } -} - -void tst_QFtp::renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete ) -{ - if ( !fileToDelete.isNull() ) { - // cleanup (i.e. remove the file) - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Remove, ftp->remove( fileToDelete ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host) ); - - ResMapIt it = resultMap.find( QFtp::Remove ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 1 ); - - QVERIFY( !fileExists( host, 21, user, password, fileToDelete ) ); - } -} - -void tst_QFtp::rename() -{ - QFETCH( QString, host ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( QString, cdDir ); - QFETCH( QString, oldfile ); - QFETCH( QString, newfile ); - QFETCH( QString, createFile ); - QFETCH( QString, renamedFile ); - - if(oldfile.contains('%')) - oldfile = oldfile.arg(uniqueExtension); - if(newfile.contains('%')) - newfile = newfile.arg(uniqueExtension); - if(createFile.contains('%')) - createFile = createFile.arg(uniqueExtension); - if(renamedFile.contains('%')) - renamedFile = renamedFile.arg(uniqueExtension); - - renameInit( host, user, password, createFile ); - - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - if ( !cdDir.isNull() ) - addCommand( QFtp::Cd, ftp->cd( cdDir ) ); - addCommand( QFtp::Rename, ftp->rename( oldfile, newfile ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host) ); - - ResMapIt it = resultMap.find( QFtp::Rename ); - QVERIFY( it != resultMap.end() ); - QTEST( it.value().success, "success" ); - - if ( it.value().success ) { - QVERIFY( !fileExists( host, 21, user, password, oldfile, cdDir ) ); - QVERIFY( fileExists( host, 21, user, password, newfile, cdDir ) ); - QVERIFY( fileExists( host, 21, user, password, renamedFile ) ); - } else { - QVERIFY( !fileExists( host, 21, user, password, newfile, cdDir ) ); - QVERIFY( !fileExists( host, 21, user, password, renamedFile ) ); - } - - renameCleanup( host, user, password, renamedFile ); -} - -/* - The commandSequence() test does not test any particular function. It rather - tests a sequence of arbitrary commands specified in the test data. -*/ -class FtpCommand -{ -public: - FtpCommand() : - cmd(QFtp::None) - { } - - FtpCommand( QFtp::Command command ) : - cmd(command) - { } - - FtpCommand( QFtp::Command command, const QStringList &arguments ) : - cmd(command), args(arguments) - { } - - FtpCommand( const FtpCommand &c ) - { *this = c; } - - FtpCommand &operator=( const FtpCommand &c ) - { - this->cmd = c.cmd; - this->args = c.args; - return *this; - } - - QFtp::Command cmd; - QStringList args; -}; -QDataStream &operator<<( QDataStream &s, const FtpCommand &command ) -{ - s << (int)command.cmd; - s << command.args; - return s; -} -QDataStream &operator>>( QDataStream &s, FtpCommand &command ) -{ - int tmp; - s >> tmp; - command.cmd = (QFtp::Command)tmp; - s >> command.args; - return s; -} -Q_DECLARE_METATYPE(QList) - -void tst_QFtp::commandSequence_data() -{ - // some "constants" - QStringList argConnectToHost01; - argConnectToHost01 << QtNetworkSettings::ftpServerName() << "21"; - - QStringList argLogin01, argLogin02, argLogin03, argLogin04; - argLogin01 << QString() << QString(); - argLogin02 << "ftp" << QString(); - argLogin03 << "ftp" << "foo"; - argLogin04 << QString("ftptest") << "password"; - - FtpCommand connectToHost01( QFtp::ConnectToHost, argConnectToHost01 ); - FtpCommand login01( QFtp::Login, argLogin01 ); - FtpCommand login02( QFtp::Login, argLogin01 ); - FtpCommand login03( QFtp::Login, argLogin01 ); - FtpCommand login04( QFtp::Login, argLogin01 ); - FtpCommand close01( QFtp::Close ); - - QTest::addColumn >("cmds"); - QTest::addColumn("success"); - - // success data - { - QList cmds; - cmds << connectToHost01; - QTest::newRow( "simple_ok01" ) << cmds << 1; - } - { - QList cmds; - cmds << connectToHost01; - cmds << login01; - QTest::newRow( "simple_ok02" ) << cmds << 1; - } - { - QList cmds; - cmds << connectToHost01; - cmds << login01; - cmds << close01; - QTest::newRow( "simple_ok03" ) << cmds << 1; - } - { - QList cmds; - cmds << connectToHost01; - cmds << close01; - QTest::newRow( "simple_ok04" ) << cmds << 1; - } - { - QList cmds; - cmds << connectToHost01; - cmds << login01; - cmds << close01; - cmds << connectToHost01; - cmds << login02; - cmds << close01; - QTest::newRow( "connect_twice" ) << cmds << 1; - } - - // error data - { - QList cmds; - cmds << close01; - QTest::newRow( "error01" ) << cmds << 0; - } - { - QList cmds; - cmds << login01; - QTest::newRow( "error02" ) << cmds << 0; - } - { - QList cmds; - cmds << login01; - cmds << close01; - QTest::newRow( "error03" ) << cmds << 0; - } - { - QList cmds; - cmds << connectToHost01; - cmds << login01; - cmds << close01; - cmds << login01; - QTest::newRow( "error04" ) << cmds << 0; - } -} - -void tst_QFtp::commandSequence() -{ - QFETCH( QList, cmds ); - - ftp = newFtp(); - QString host; - quint16 port = 0; - QList::iterator it; - for ( it = cmds.begin(); it != cmds.end(); ++it ) { - switch ( (*it).cmd ) { - case QFtp::ConnectToHost: - { - QCOMPARE( (*it).args.count(), 2 ); - bool portOk; - port = (*it).args[1].toUShort( &portOk ); - QVERIFY( portOk ); - host = (*it).args[0]; - ids << ftp->connectToHost( host, port ); - } - break; - case QFtp::Login: - QCOMPARE( (*it).args.count(), 2 ); - ids << ftp->login( (*it).args[0], (*it).args[1] ); - break; - case QFtp::Close: - QCOMPARE( (*it).args.count(), 0 ); - ids << ftp->close(); - break; - default: - QFAIL( "Error in test: unexpected enum value" ); - break; - } - } - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host) ); - - QTEST( commandSequence_success, "success" ); -} - -void tst_QFtp::abort_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("file"); - QTest::addColumn("uploadData"); - - QTest::newRow( "get_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/bigfile") << QByteArray(); - QTest::newRow( "get_fluke02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/rfc3252") << QByteArray(); - - // Qt/CE test environment has too little memory for this test - QByteArray bigData( 10*1024*1024, 0 ); - bigData.fill( 'B' ); - QTest::newRow( "put_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/upload/abort_put") << bigData; -} - -void tst_QFtp::abort() -{ - QSKIP("This test takes too long."); - // In case you wonder where the abort() actually happens, look into - // tst_QFtp::dataTransferProgress - // - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, file ); - QFETCH( QByteArray, uploadData ); - - QFtp::Command cmd; - if ( uploadData.size() == 0 ) - cmd = QFtp::Get; - else - cmd = QFtp::Put; - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login() ); - if ( cmd == QFtp::Get ) - addCommand( cmd, ftp->get( file ) ); - else - addCommand( cmd, ftp->put( uploadData, file ) ); - addCommand( QFtp::Close, ftp->close() ); - - for(int time = 0; time <= uploadData.length() / 30000; time += 30) { - QTestEventLoop::instance().enterLoop( 50 ); - if(ftp->currentCommand() == QFtp::None) - break; - } - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - ResMapIt it = resultMap.find( cmd ); - QVERIFY( it != resultMap.end() ); - // ### how to test the abort? - if ( it.value().success ) { - // The FTP server on fluke is sadly returning a success, even when - // the operation was aborted. So we have to use some heuristics. - if ( host == QtNetworkSettings::ftpServerName() ) { - if ( cmd == QFtp::Get ) { - QVERIFY2(bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal)); - } else { - // put commands should always be aborted, since we use really - // big data - QVERIFY2( bytesDone != bytesTotal, msgComparison(bytesDone, "!=", bytesTotal) ); - } - } else { - // this could be tested by verifying that no more progress signals are emitted - QVERIFY2(bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal)); - } - } else { - QVERIFY2( bytesDone != bytesTotal, msgComparison(bytesDone, "!=", bytesTotal) ); - } - - if ( cmd == QFtp::Put ) { - ////////////////////////////////////// - // cleanup (i.e. remove the file) - init(); - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login() ); - addCommand( QFtp::Remove, ftp->remove( file ) ); - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host, port) ); - - it = resultMap.find( QFtp::Remove ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 1 ); - } -} - -void tst_QFtp::bytesAvailable_data() -{ - QTest::addColumn("host"); - QTest::addColumn("file"); - QTest::addColumn("type"); - QTest::addColumn("bytesAvailFinishedGet"); - QTest::addColumn("bytesAvailFinished"); - QTest::addColumn("bytesAvailDone"); - - QTest::newRow( "fluke01" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 0 << (qlonglong)519240 << (qlonglong)519240 << (qlonglong)519240; - QTest::newRow( "fluke02" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 0 << (qlonglong)25962 << (qlonglong)25962 << (qlonglong)25962; - - QTest::newRow( "fluke03" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 1 << (qlonglong)519240 << (qlonglong)0 << (qlonglong)0; - QTest::newRow( "fluke04" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 1 << (qlonglong)25962 << (qlonglong)0 << (qlonglong)0; -} - -void tst_QFtp::bytesAvailable() -{ - QFETCH( QString, host ); - QFETCH( QString, file ); - QFETCH( int, type ); - - ftp = newFtp(); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); - addCommand( QFtp::Login, ftp->login() ); - addCommand( QFtp::Get, ftp->get( file ) ); - if ( type != 0 ) - addCommand( QFtp::Close, ftp->close() ); - - QTestEventLoop::instance().enterLoop( 40 ); - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(host) ); - - ResMapIt it = resultMap.find( QFtp::Get ); - QVERIFY( it != resultMap.end() ); - QVERIFY( it.value().success ); - - QFETCH(qlonglong, bytesAvailFinishedGet); - QCOMPARE(bytesAvailable_finishedGet, bytesAvailFinishedGet); - - QFETCH(qlonglong, bytesAvailFinished); - QCOMPARE(bytesAvailable_finished, bytesAvailFinished); - - QFETCH(qlonglong, bytesAvailDone); - QCOMPARE(bytesAvailable_done, bytesAvailDone); - - ftp->readAll(); - QCOMPARE( ftp->bytesAvailable(), 0 ); - delete ftp; - ftp = 0; -} - -void tst_QFtp::activeMode() -{ - QFile file("tst_QFtp_activeMode_inittab"); - file.open(QIODevice::ReadWrite); - QFtp ftp; - ftp.setTransferMode(QFtp::Active); - ftp.connectToHost(QtNetworkSettings::ftpServerName(), 21); - ftp.login(); - ftp.list(); - ftp.get("/qtest/rfc3252.txt", &file); - connect(&ftp, SIGNAL(done(bool)), SLOT(activeModeDone(bool))); - QTestEventLoop::instance().enterLoop(900); - QFile::remove("tst_QFtp_activeMode_inittab"); - QCOMPARE(done_success, 1); - -} - -void tst_QFtp::activeModeDone(bool error) -{ - done_success = error ? -1 : 1; - QTestEventLoop::instance().exitLoop(); -} - -void tst_QFtp::proxy_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("dir"); - QTest::addColumn("success"); - QTest::addColumn("entryNames"); // ### we should rather use a QList here - - QStringList flukeRoot; - flukeRoot << "qtest"; - QStringList flukeQtest; - flukeQtest << "bigfile"; - flukeQtest << "nonASCII"; - flukeQtest << "rfc3252"; - flukeQtest << "rfc3252.txt"; - flukeQtest << "upload"; - - QTest::newRow( "proxy_relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; - QTest::newRow( "proxy_relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; - - QTest::newRow( "proxy_absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; - QTest::newRow( "proxy_absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; - - QTest::newRow( "proxy_nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); - QTest::newRow( "proxy_nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); -} - -void tst_QFtp::proxy() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, user ); - QFETCH( QString, password ); - QFETCH( QString, dir ); - - ftp = newFtp(); - addCommand( QFtp::SetProxy, ftp->setProxy( QtNetworkSettings::ftpProxyServerName(), 2121 ) ); - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - addCommand( QFtp::Cd, ftp->cd( dir ) ); - addCommand( QFtp::List, ftp->list() ); - - QTestEventLoop::instance().enterLoop( 50 ); - - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) { - QFAIL( msgTimedOut(host, port) ); - } - - ResMapIt it = resultMap.find( QFtp::Cd ); - QVERIFY( it != resultMap.end() ); - QFETCH( int, success ); - QCOMPARE( it.value().success, success ); - QFETCH( QStringList, entryNames ); - QCOMPARE( listInfo_i.count(), entryNames.count() ); - for ( uint i=0; i < (uint) entryNames.count(); i++ ) { - QCOMPARE( listInfo_i[i].name(), entryNames[i] ); - } -} - -void tst_QFtp::binaryAscii() -{ - QString file = "asciifile%1.txt"; - - if(file.contains('%')) - file = file.arg(uniqueExtension); - - QByteArray putData = "a line of text\r\n"; - - init(); - ftp = newFtp(); - addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21)); - addCommand(QFtp::Login, ftp->login("ftptest", "password")); - addCommand(QFtp::Cd, ftp->cd("qtest/upload")); - addCommand(QFtp::Put, ftp->put(putData, file, QFtp::Ascii)); - addCommand(QFtp::Close, ftp->close()); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) ); - - ResMapIt it = resultMap.find(QFtp::Put); - QVERIFY(it != resultMap.end()); - QVERIFY(it.value().success); - - QByteArray getData; - QBuffer getBuf(&getData); - getBuf.open(QBuffer::WriteOnly); - - init(); - ftp = newFtp(); - addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21)); - addCommand(QFtp::Login, ftp->login("ftptest", "password")); - addCommand(QFtp::Cd, ftp->cd("qtest/upload")); - addCommand(QFtp::Get, ftp->get(file, &getBuf, QFtp::Binary)); - addCommand(QFtp::Close, ftp->close()); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) ); - - ResMapIt it2 = resultMap.find(QFtp::Get); - QVERIFY(it2 != resultMap.end()); - QVERIFY(it2.value().success); - // most modern ftp servers leave the file as it is by default - // (and do not remove the windows line ending), the -1 below could be - // deleted in the future - QCOMPARE(getData.size(), putData.size() - 1); - ////////////////////////////////////////////////////////////////// - // cleanup (i.e. remove the file) -- this also tests the remove command - init(); - ftp = newFtp(); - addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21)); - addCommand(QFtp::Login, ftp->login("ftptest", "password")); - addCommand(QFtp::Cd, ftp->cd("qtest/upload")); - addCommand(QFtp::Remove, ftp->remove(file)); - addCommand(QFtp::Close, ftp->close()); - - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) - QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) ); - - it = resultMap.find( QFtp::Remove ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, 1 ); - - QVERIFY(!fileExists(QtNetworkSettings::ftpServerName(), 21, "ftptest", "password", file)); -} - - -// test QFtp::currentId() and QFtp::currentCommand() -#define CURRENTCOMMAND_TEST \ -{ \ - ResMapIt it; \ - for ( it = resultMap.begin(); it != resultMap.end(); ++it ) { \ - if ( it.value().id == ftp->currentId() ) { \ - QVERIFY( it.key() == ftp->currentCommand() ); \ - } \ -} \ -} - -void tst_QFtp::commandStarted( int id ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d:commandStarted( %d )", ftp->currentId(), id ); -#endif - // make sure that the commandStarted and commandFinished are nested correctly - QCOMPARE( current_id, 0 ); - current_id = id; - - QVERIFY( !ids.isEmpty() ); - QCOMPARE( ids.first(), id ); - if ( ids.count() > 1 ) { - QVERIFY( ftp->hasPendingCommands() ); - } else { - QVERIFY( !ftp->hasPendingCommands() ); - } - - QVERIFY( ftp->currentId() == id ); - QCOMPARE( cur_state, int(ftp->state()) ); - CURRENTCOMMAND_TEST; - - QCOMPARE( ftp->error(), QFtp::NoError ); -} - -void tst_QFtp::commandFinished( int id, bool error ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d:commandFinished( %d, %d ) -- errorString: '%s'", - ftp->currentId(), id, (int)error, ftp->errorString().toLatin1().constData() ); -#endif - if ( ftp->currentCommand() == QFtp::Get ) { - bytesAvailable_finishedGet = ftp->bytesAvailable(); - } - bytesAvailable_finished = ftp->bytesAvailable(); - - // make sure that the commandStarted and commandFinished are nested correctly - QCOMPARE( current_id, id ); - current_id = 0; - - QVERIFY( !ids.isEmpty() ); - QCOMPARE( ids.first(), id ); - if ( !error && ids.count() > 1) { - QVERIFY( ftp->hasPendingCommands() ); - } else { - QVERIFY( !ftp->hasPendingCommands() ); - } - if ( error ) { - QVERIFY2( ftp->error() != QFtp::NoError, msgComparison(ftp->error(), "!=", QFtp::NoError) ); - ids.clear(); - } else { - QCOMPARE( ftp->error(), QFtp::NoError ); - ids.pop_front(); - } - - QCOMPARE( ftp->currentId(), id ); - QCOMPARE( cur_state, int(ftp->state()) ); - CURRENTCOMMAND_TEST; - - if ( QTest::currentTestFunction() != QLatin1String("commandSequence") ) { - ResMapIt it = resultMap.find( ftp->currentCommand() ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( it.value().success, -1 ); - if ( error ) - it.value().success = 0; - else - it.value().success = 1; - } -} - -void tst_QFtp::done( bool error ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d:done( %d )", ftp->currentId(), (int)error ); -#endif - bytesAvailable_done = ftp->bytesAvailable(); - - QCOMPARE( ftp->currentId(), 0 ); - QVERIFY( current_id == 0 ); - QVERIFY( ids.isEmpty() ); - QVERIFY( cur_state == ftp->state() ); - QVERIFY( !ftp->hasPendingCommands() ); - - if ( QTest::currentTestFunction() == QLatin1String("commandSequence") ) { - QCOMPARE( commandSequence_success, -1 ); - if ( error ) - commandSequence_success = 0; - else - commandSequence_success = 1; - } - QCOMPARE( done_success, -1 ); - if ( error ) { - QVERIFY2( ftp->error() != QFtp::NoError, msgComparison(ftp->error(), "!=", QFtp::NoError) ); - done_success = 0; - } else { - QCOMPARE( ftp->error(), QFtp::NoError ); - done_success = 1; - } - QTestEventLoop::instance().exitLoop(); -} - -void tst_QFtp::stateChanged( int state ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: stateChanged( %d )", ftp->currentId(), state ); -#endif - QCOMPARE( ftp->currentId(), current_id ); - CURRENTCOMMAND_TEST; - - QVERIFY2( state != cur_state, msgComparison(state, "!=", cur_state) ); - QCOMPARE( state, (int)ftp->state() ); - if ( state != QFtp::Unconnected ) { - // make sure that the states are always emitted in the right order (for - // this, we assume an ordering on the enum values, which they have at - // the moment) - QVERIFY2( cur_state < state, msgComparison(cur_state, "<", state) ); - - // make sure that state changes are only emitted in response to certain - // commands - switch ( state ) { - case QFtp::HostLookup: - case QFtp::Connecting: - case QFtp::Connected: - QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::ConnectToHost ); - break; - case QFtp::LoggedIn: - QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Login ); - break; - case QFtp::Closing: - QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Close ); - break; - default: - QWARN( QString("Unexpected state '%1'").arg(state).toLatin1().constData() ); - break; - } - } - cur_state = state; - - if ( QTest::currentTestFunction() == QLatin1String("connectToHost") ) { - switch ( state ) { - case QFtp::HostLookup: - case QFtp::Connecting: - case QFtp::LoggedIn: - case QFtp::Closing: - // ignore - break; - case QFtp::Connected: - case QFtp::Unconnected: - QVERIFY( connectToHost_state == -1 ); - connectToHost_state = state; - break; - default: - QWARN( QString("Unknown state '%1'").arg(state).toLatin1().constData() ); - break; - } - } else if ( QTest::currentTestFunction() == QLatin1String("close") ) { - ResMapIt it = resultMap.find( QFtp::Close ); - if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) { - if ( state == QFtp::Closing ) { - QCOMPARE( close_state, -1 ); - close_state = state; - } else if ( state == QFtp::Unconnected ) { - QCOMPARE(close_state, int(QFtp::Closing) ); - close_state = state; - } - } - } else if ( QTest::currentTestFunction() == QLatin1String("login") ) { - ResMapIt it = resultMap.find( QFtp::Login ); - if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) { - if ( state == QFtp::LoggedIn ) { - QCOMPARE( login_state, -1 ); - login_state = state; - } - } - } -} - -void tst_QFtp::listInfo( const QUrlInfo &i ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: listInfo( %s )", ftp->currentId(), i.name().toLatin1().constData() ); -#endif - QCOMPARE( ftp->currentId(), current_id ); - if ( ids.count() > 1 ) { - QVERIFY( ftp->hasPendingCommands() ); - } else { - QVERIFY( !ftp->hasPendingCommands() ); - } - QCOMPARE( cur_state, int(ftp->state()) ); - CURRENTCOMMAND_TEST; - - if ( QTest::currentTestFunction()==QLatin1String("list") || QTest::currentTestFunction()==QLatin1String("cd") || QTest::currentTestFunction()==QLatin1String("proxy") || inFileDirExistsFunction ) { - ResMapIt it = resultMap.find( QFtp::List ); - QVERIFY( it != resultMap.end() ); - QCOMPARE( ftp->currentId(), it.value().id ); - listInfo_i << i; - } -} - -void tst_QFtp::readyRead() -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: readyRead(), bytesAvailable == %lu", ftp->currentId(), ftp->bytesAvailable() ); -#endif - QCOMPARE( ftp->currentId(), current_id ); - if ( ids.count() > 1 ) { - QVERIFY( ftp->hasPendingCommands() ); - } else { - QVERIFY( !ftp->hasPendingCommands() ); - } - QVERIFY( cur_state == ftp->state() ); - CURRENTCOMMAND_TEST; - - if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) { - int oldSize = newData_ba.size(); - qlonglong bytesAvail = ftp->bytesAvailable(); - QByteArray ba = ftp->readAll(); - QCOMPARE( ba.size(), (int) bytesAvail ); - newData_ba.resize( oldSize + ba.size() ); - memcpy( newData_ba.data()+oldSize, ba.data(), ba.size() ); - - if ( bytesTotal != -1 ) { - QVERIFY2( (int)newData_ba.size() <= bytesTotal, msgComparison(newData_ba.size(), "<=", bytesTotal) ); - } - QCOMPARE( qlonglong(newData_ba.size()), bytesDone ); - } -} - -void tst_QFtp::dataTransferProgress( qint64 done, qint64 total ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: dataTransferProgress( %lli, %lli )", ftp->currentId(), done, total ); -#endif - QCOMPARE( ftp->currentId(), current_id ); - if ( ids.count() > 1 ) { - QVERIFY( ftp->hasPendingCommands() ); - } else { - QVERIFY( !ftp->hasPendingCommands() ); - } - QCOMPARE( cur_state, int(ftp->state()) ); - CURRENTCOMMAND_TEST; - - if ( bytesTotal == bytesTotal_init ) { - bytesTotal = total; - } else { - QCOMPARE( bytesTotal, total ); - } - - QVERIFY2( bytesTotal != bytesTotal_init, msgComparison(bytesTotal, "!=", bytesTotal_init) ); - QVERIFY2( bytesDone <= done, msgComparison(bytesDone, "<=", done) ); - bytesDone = done; - if ( bytesTotal != -1 ) { - QVERIFY2( bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal) ); - } - - if ( QTest::currentTestFunction() == QLatin1String("abort") ) { - // ### it would be nice if we could specify in our testdata when to do - // the abort - if ( done >= total/100000 ) { - if ( ids.count() != 1 ) { - // do abort only once - int tmpId = ids.first(); - ids.clear(); - ids << tmpId; - ftp->abort(); - } - } - } -} - - -QFtp *tst_QFtp::newFtp() -{ - QFtp *nFtp = new QFtp( this ); - connect( nFtp, SIGNAL(commandStarted(int)), - SLOT(commandStarted(int)) ); - connect( nFtp, SIGNAL(commandFinished(int,bool)), - SLOT(commandFinished(int,bool)) ); - connect( nFtp, SIGNAL(done(bool)), - SLOT(done(bool)) ); - connect( nFtp, SIGNAL(stateChanged(int)), - SLOT(stateChanged(int)) ); - connect( nFtp, SIGNAL(listInfo(QUrlInfo)), - SLOT(listInfo(QUrlInfo)) ); - connect( nFtp, SIGNAL(readyRead()), - SLOT(readyRead()) ); - connect( nFtp, SIGNAL(dataTransferProgress(qint64,qint64)), - SLOT(dataTransferProgress(qint64,qint64)) ); - - return nFtp; -} - -void tst_QFtp::addCommand( QFtp::Command cmd, int id ) -{ - ids << id; - CommandResult res; - res.id = id; - res.success = -1; - resultMap[ cmd ] = res; -} - -bool tst_QFtp::fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir ) -{ - init(); - ftp = newFtp(); - // ### make these tests work - if (ftp->currentId() != 0) { - qWarning("ftp->currentId() != 0"); - return false; - } - - if (ftp->state() != QFtp::Unconnected) { - qWarning("ftp->state() != QFtp::Unconnected"); - return false; - } - - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - if ( !cdDir.isNull() ) - addCommand( QFtp::Cd, ftp->cd( cdDir ) ); - addCommand( QFtp::List, ftp->list( file ) ); - addCommand( QFtp::Close, ftp->close() ); - - inFileDirExistsFunction = true; - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) { - // ### make this test work - qWarning("tst_QFtp::fileExists: Network operation timed out"); - return false; - } - inFileDirExistsFunction = false; - - ResMapIt it = resultMap.find( QFtp::ConnectToHost ); - // ### make these tests work - if (it == resultMap.end()) { - qWarning("it != resultMap.end()"); - return false; - } - - if (it.value().success == -1) { - qWarning("it.value().success != -1"); - return false; - } - - if ( it.value().success == 1 ) { - for ( uint i=0; i < (uint) listInfo_i.count(); i++ ) { - if ( QFileInfo(listInfo_i[i].name()).fileName() == QFileInfo(file).fileName() ) - return true; - } - } - - //this is not a good warning considering sometime this function is used to test that a file does not exist - //qWarning("file doesn't exist"); - return false; -} - -bool tst_QFtp::dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate ) -{ - init(); - ftp = newFtp(); - // ### make these tests work - // QCOMPARE( ftp->currentId(), 0 ); - // QCOMPARE( (int)ftp->state(), (int)QFtp::Unconnected ); - - addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); - addCommand( QFtp::Login, ftp->login( user, password ) ); - if ( dirToCreate.startsWith( QLatin1Char('/') ) ) - addCommand( QFtp::Cd, ftp->cd( dirToCreate ) ); - else - addCommand( QFtp::Cd, ftp->cd( cdDir + QLatin1Char('/') + dirToCreate ) ); - addCommand( QFtp::Close, ftp->close() ); - - inFileDirExistsFunction = true; - QTestEventLoop::instance().enterLoop( 30 ); - delete ftp; - ftp = 0; - if ( QTestEventLoop::instance().timeout() ) { - // ### make this test work - // QFAIL( msgTimedOut(host, port) ); - qWarning("tst_QFtp::dirExists: Network operation timed out"); - return false; - } - inFileDirExistsFunction = false; - - ResMapIt it = resultMap.find( QFtp::Cd ); - // ### make these tests work - // QVERIFY( it != resultMap.end() ); - // QVERIFY( it.value().success != -1 ); - return it.value().success == 1; -} - -void tst_QFtp::doneSignal() -{ - QFtp ftp; - QSignalSpy spy(&ftp, SIGNAL(done(bool))); - - ftp.connectToHost(QtNetworkSettings::ftpServerName()); - ftp.login("anonymous"); - ftp.list(); - ftp.close(); - - done_success = 0; - connect(&ftp, SIGNAL(done(bool)), &(QTestEventLoop::instance()), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(61); - if (QTestEventLoop::instance().timeout()) - QFAIL("Network operation timed out"); - - QCOMPARE(spy.count(), 1); - QCOMPARE(spy.first().first().toBool(), false); -} - -void tst_QFtp::queueMoreCommandsInDoneSlot() -{ - QSKIP("Task 127050 && 113966"); - - QFtp ftp; - QSignalSpy doneSpy(&ftp, SIGNAL(done(bool))); - QSignalSpy commandFinishedSpy(&ftp, SIGNAL(commandFinished(int,bool))); - - this->ftp = &ftp; - connect(&ftp, SIGNAL(done(bool)), this, SLOT(cdUpSlot(bool))); - - ftp.connectToHost("ftp.qt-project.org"); - ftp.login(); - ftp.cd("qt"); - ftp.rmdir("qtest-removedir-noexist"); - - while ( ftp.hasPendingCommands() || ftp.currentCommand() != QFtp::None ) { - QCoreApplication::instance()->processEvents(QEventLoop::AllEvents - | QEventLoop::WaitForMoreEvents); - } - - QCOMPARE(doneSpy.count(), 2); - QCOMPARE(doneSpy.first().first().toBool(), true); - QCOMPARE(doneSpy.last().first().toBool(), false); - - QCOMPARE(commandFinishedSpy.count(), 6); - int firstId = commandFinishedSpy.at(0).at(0).toInt(); - QCOMPARE(commandFinishedSpy.at(0).at(1).toBool(), false); - QCOMPARE(commandFinishedSpy.at(1).at(0).toInt(), firstId + 1); - QCOMPARE(commandFinishedSpy.at(1).at(1).toBool(), false); - QCOMPARE(commandFinishedSpy.at(2).at(0).toInt(), firstId + 2); - QCOMPARE(commandFinishedSpy.at(2).at(1).toBool(), false); - QCOMPARE(commandFinishedSpy.at(3).at(0).toInt(), firstId + 3); - QCOMPARE(commandFinishedSpy.at(3).at(1).toBool(), true); - QCOMPARE(commandFinishedSpy.at(4).at(0).toInt(), firstId + 4); - QCOMPARE(commandFinishedSpy.at(4).at(1).toBool(), false); - QCOMPARE(commandFinishedSpy.at(5).at(0).toInt(), firstId + 5); - QCOMPARE(commandFinishedSpy.at(5).at(1).toBool(), false); - - this->ftp = 0; -} - -void tst_QFtp::cdUpSlot(bool error) -{ - if (error) { - ftp->cd(".."); - ftp->cd("qt"); - } -} - -void tst_QFtp::qtbug7359Crash() -{ - QFtp ftp; - ftp.connectToHost("127.0.0.1"); - - QElapsedTimer t; - int elapsed; - - t.start(); - while ((elapsed = t.elapsed()) < 200) - QCoreApplication::processEvents(QEventLoop::AllEvents, 200 - elapsed); - - ftp.close(); - t.restart(); - while ((elapsed = t.elapsed()) < 1000) - QCoreApplication::processEvents(QEventLoop::AllEvents, 1000 - elapsed); - - ftp.connectToHost("127.0.0.1"); - - t.restart(); - while ((elapsed = t.elapsed()) < 2000) - QCoreApplication::processEvents(QEventLoop::AllEvents, 2000 - elapsed); -} - -class FtpLocalServer : public QTcpServer -{ - Q_OBJECT - -public: - explicit FtpLocalServer(QObject *parent = 0) : QTcpServer(parent) {} - virtual ~FtpLocalServer() { delete mSocket; } - void startServer(qint16 port = 0); - void stopServer(); - - enum class ReplyCodes { - ServiceReady = 220, - ServiceClose = 221, - NeedPassword = 331, - LoginFailed = 530, - RequestDeny = 550 - }; - - void sendResponse(ReplyCodes code); - - inline QString getRawUser() { return rawUser; } - inline QString getRawPassword() { return rawPass; } - -signals: - void onStarted(); - void onStopped(); - -public slots: - void socketReadyRead(); - void socketDisconnected(); - -protected: - virtual void incomingConnection(qintptr handle); - -private: - QTcpSocket *mSocket = nullptr; - QString rawUser; - QString rawPass; -}; - -void FtpLocalServer::startServer(qint16 port) -{ - if (listen(QHostAddress::Any, port)) - emit onStarted(); // Notify connected objects - else - qDebug("Could not start FTP server"); -} - -void FtpLocalServer::stopServer() -{ - close(); - emit onStopped(); // Notify connected objects -} - -void FtpLocalServer::sendResponse(ReplyCodes code) -{ - if (mSocket) - { - QString response; - switch (code) { - case ReplyCodes::ServiceReady: - response = QString("220 Service ready for new user.\r\n"); - break; - case ReplyCodes::ServiceClose: - response = QString("221 Service closing control connection.\r\n"); - break; - case ReplyCodes::NeedPassword: - response = QString("331 User name okay, need password.\r\n"); - break; - case ReplyCodes::LoginFailed: - response = QString("530 Not logged in.\r\n"); - break; - case ReplyCodes::RequestDeny: - response = QString("550 Requested action not taken.\r\n"); - break; - default: - qDebug("Unimplemented response code: %u", static_cast(code)); - break; - } - - if (!response.isEmpty()) - mSocket->write(response.toLatin1()); - } -} - -void FtpLocalServer::incomingConnection(qintptr handle) -{ - mSocket = new QTcpSocket(this); - if (mSocket == nullptr || !mSocket->setSocketDescriptor(handle)) - { - delete mSocket; - mSocket = nullptr; - qDebug() << handle << " Error binding socket"; - return; - } - - connect(mSocket, SIGNAL(readyRead()), this, SLOT(socketReadyRead())); - connect(mSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); - - // Accept client connection - sendResponse(ReplyCodes::ServiceReady); -} - -void FtpLocalServer::socketReadyRead() -{ - QString data; - if (mSocket) - data.append(mSocket->readAll()); - - // RFC959 Upper and lower case alphabetic characters are to be treated identically. - if (data.startsWith("USER", Qt::CaseInsensitive)) { - rawUser = data; - sendResponse(ReplyCodes::NeedPassword); - } else if (data.startsWith("PASS", Qt::CaseInsensitive)) { - rawPass = data; - sendResponse(ReplyCodes::LoginFailed); - } else { - sendResponse(ReplyCodes::RequestDeny); - } -} - -void FtpLocalServer::socketDisconnected() -{ - // Cleanup - if (mSocket) - mSocket->deleteLater(); - deleteLater(); -} - -void tst_QFtp::loginURL_data() -{ - QTest::addColumn("user"); - QTest::addColumn("password"); - QTest::addColumn("rawUser"); - QTest::addColumn("rawPass"); - - QTest::newRow("no username, no password") - << QString() << QString() - << QString("USER anonymous\r\n") << QString("PASS anonymous@\r\n"); - - QTest::newRow("username, no password") - << QString("someone") << QString() - << QString("USER someone\r\n") << QString(); - - QTest::newRow("username, empty password") - << QString("someone") << QString("") - << QString("USER someone\r\n") << QString("PASS \r\n"); - - QTest::newRow("username, password") - << QString("someone") << QString("nonsense") - << QString("USER someone\r\n") << QString("PASS nonsense\r\n"); - - QTest::newRow("anonymous, no password") - << QString("anonymous") << QString() - << QString("USER anonymous\r\n") << QString("PASS anonymous@\r\n"); - - QTest::newRow("Anonymous, no password") - << QString("Anonymous") << QString() - << QString("USER Anonymous\r\n") << QString("PASS anonymous@\r\n"); - - QTest::newRow("anonymous, empty password") - << QString("anonymous") << QString("") - << QString("USER anonymous\r\n") << QString("PASS \r\n"); - - QTest::newRow("ANONYMOUS, password") - << QString("ANONYMOUS") << QString("nonsense") - << QString("USER ANONYMOUS\r\n") << QString("PASS nonsense\r\n"); -} - -void tst_QFtp::loginURL() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - QSKIP("This test should be verified on the local machine without proxies"); - - QFETCH(QString, user); - QFETCH(QString, password); - QFETCH(QString, rawUser); - QFETCH(QString, rawPass); - - FtpLocalServer server; - server.startServer(); - uint port = server.serverPort(); - - ftp = newFtp(); - addCommand(QFtp::ConnectToHost, - ftp->connectToHost("127.0.0.1", port)); - addCommand(QFtp::Login, ftp->login(user, password)); - - QTestEventLoop::instance().enterLoop(5); - delete ftp; - ftp = nullptr; - server.stopServer(); - if (QTestEventLoop::instance().timeout()) - QFAIL(msgTimedOut("127.0.0.1", port)); - - QCOMPARE(server.getRawUser(), rawUser); - QCOMPARE(server.getRawPassword(), rawPass); -} - -QTEST_MAIN(tst_QFtp) - -#include "tst_qftp.moc" diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index c8be0902ba..e470dd02b4 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -208,11 +208,9 @@ private Q_SLOTS: void getFromFile(); void getFromFileSpecial_data(); void getFromFileSpecial(); -#if QT_CONFIG(ftp) void getFromFtp_data(); void getFromFtp(); void getFromFtpAfterError(); // QTBUG-40797 -#endif void getFromHttp_data(); void getFromHttp(); void getErrors_data(); @@ -223,11 +221,9 @@ private Q_SLOTS: #endif // !QT_NO_NETWORKPROXY void putToFile_data(); void putToFile(); -#if QT_CONFIG(ftp) void putToFtp_data(); void putToFtp(); void putToFtpWithInvalidCredentials(); // QTBUG-40622 -#endif void putToHttp_data(); void putToHttp(); void putToHttpSynchronous_data(); @@ -268,11 +264,9 @@ private Q_SLOTS: void ioGetFromFileSpecial(); void ioGetFromFile_data(); void ioGetFromFile(); -#if QT_CONFIG(ftp) void ioGetFromFtp_data(); void ioGetFromFtp(); void ioGetFromFtpWithReuse(); -#endif void ioGetFromHttp(); void ioGetFromBuiltinHttp_data(); @@ -314,10 +308,8 @@ private Q_SLOTS: void ioPutToFileFromLocalSocket(); void ioPutToFileFromProcess_data(); void ioPutToFileFromProcess(); -#if QT_CONFIG(ftp) void ioPutToFtpFromFile_data(); void ioPutToFtpFromFile(); -#endif void ioPutToHttpFromFile_data(); void ioPutToHttpFromFile(); void ioPostToHttpFromFile_data(); @@ -464,10 +456,8 @@ private Q_SLOTS: void closeDuringDownload_data(); void closeDuringDownload(); -#if QT_CONFIG(ftp) void ftpAuthentication_data(); void ftpAuthentication(); -#endif void emitErrorForAllReplies(); // QTBUG-36890 @@ -517,6 +507,8 @@ private: QString testDataDir; bool notEnoughDataForFastSender; + + bool ftpSupported = false; }; const QByteArray tst_QNetworkReply::httpEmpty200Response = @@ -1320,6 +1312,8 @@ tst_QNetworkReply::tst_QNetworkReply() #ifndef QT_NO_NETWORKPROXY } #endif // !QT_NO_NETWORKPROXY + + ftpSupported = manager.supportedSchemes().contains("ftp"); } tst_QNetworkReply::~tst_QNetworkReply() @@ -1836,9 +1830,10 @@ void tst_QNetworkReply::getFromFileSpecial() QCOMPARE(reply->readAll(), resource.readAll()); } -#if QT_CONFIG(ftp) void tst_QNetworkReply::getFromFtp_data() { + if (!ftpSupported) + QSKIP("FTP is not supported"); QTest::addColumn("referenceName"); QTest::addColumn("url"); @@ -1872,6 +1867,9 @@ void tst_QNetworkReply::getFromFtp() void tst_QNetworkReply::getFromFtpAfterError() { + if (!ftpSupported) + QSKIP("FTP is not supported"); + QNetworkRequest invalidRequest(QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/invalid.txt")); QNetworkReplyPtr invalidReply; invalidReply.reset(manager.get(invalidRequest)); @@ -1889,7 +1887,6 @@ void tst_QNetworkReply::getFromFtpAfterError() QCOMPARE(validReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); QCOMPARE(validReply->readAll(), reference.readAll()); } -#endif void tst_QNetworkReply::getFromHttp_data() { @@ -2059,21 +2056,26 @@ void tst_QNetworkReply::getErrors_data() QTest::newRow("file-permissions") << "file:" + filePermissionFileName << int(QNetworkReply::ContentAccessDenied) << 0 << true; -#if QT_CONFIG(ftp) - // ftp: errors - QTest::newRow("ftp-host") << "ftp://invalid.test.qt-project.org/foo.txt" - << int(QNetworkReply::HostNotFoundError) << 0 << true; - QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::ftpServerName() - << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; - QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest" - << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; - QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/dir-not-readable/foo.txt" - << int(QNetworkReply::ContentAccessDenied) << 0 << true; - QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/file-not-readable.txt" - << int(QNetworkReply::ContentAccessDenied) << 0 << true; - QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/this-file-doesnt-exist.txt" - << int(QNetworkReply::ContentNotFoundError) << 0 << true; -#endif + if (ftpSupported) { + // ftp: errors + QTest::newRow("ftp-host") << "ftp://invalid.test.qt-project.org/foo.txt" + << int(QNetworkReply::HostNotFoundError) << 0 << true; + QTest::newRow("ftp-no-path") + << "ftp://" + QtNetworkSettings::ftpServerName() + << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; + QTest::newRow("ftp-is-dir") + << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest" + << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; + QTest::newRow("ftp-dir-not-readable") + << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/dir-not-readable/foo.txt" + << int(QNetworkReply::ContentAccessDenied) << 0 << true; + QTest::newRow("ftp-file-not-readable") + << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/file-not-readable.txt" + << int(QNetworkReply::ContentAccessDenied) << 0 << true; + QTest::newRow("ftp-exist") + << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/this-file-doesnt-exist.txt" + << int(QNetworkReply::ContentNotFoundError) << 0 << true; + } // http: errors QTest::newRow("http-host") << "http://invalid.test.qt-project.org/" @@ -2127,11 +2129,9 @@ void tst_QNetworkReply::getErrors() QVERIFY2(waitResult != Timeout, msgGetErrors(waitResult, reply)); QFETCH(int, error); -#if QT_CONFIG(ftp) QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort); // the line below is not necessary QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort); -#endif QCOMPARE(reply->error(), QNetworkReply::NetworkError(error)); QTEST(reply->readAll().isEmpty(), "dataIsEmpty"); @@ -2201,9 +2201,10 @@ void tst_QNetworkReply::putToFile() QCOMPARE(contents, data); } -#if QT_CONFIG(ftp) void tst_QNetworkReply::putToFtp_data() { + if (!ftpSupported) + QSKIP("FTP is not supported"); putToFile_data(); } @@ -2255,6 +2256,8 @@ void tst_QNetworkReply::putToFtp() void tst_QNetworkReply::putToFtpWithInvalidCredentials() { + if (!ftpSupported) + QSKIP("FTP is not supported"); QUrl url("ftp://" + QtNetworkSettings::ftpServerName()); url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2") .arg(QTest::currentDataTag()) @@ -2274,7 +2277,6 @@ void tst_QNetworkReply::putToFtpWithInvalidCredentials() r->close(); } } -#endif void tst_QNetworkReply::putToHttp_data() { @@ -3275,9 +3277,10 @@ void tst_QNetworkReply::ioGetFromFile() QCOMPARE(reader.data, data); } -#if QT_CONFIG(ftp) void tst_QNetworkReply::ioGetFromFtp_data() { + if (!ftpSupported) + QSKIP("FTP is not supported"); QTest::addColumn("fileName"); QTest::addColumn("expectedSize"); @@ -3312,6 +3315,8 @@ void tst_QNetworkReply::ioGetFromFtp() void tst_QNetworkReply::ioGetFromFtpWithReuse() { + if (!ftpSupported) + QSKIP("FTP is not supported"); QString fileName = testDataDir + "/rfc3252.txt"; QFile reference(fileName); reference.open(QIODevice::ReadOnly); @@ -3342,7 +3347,6 @@ void tst_QNetworkReply::ioGetFromFtpWithReuse() QCOMPARE(reader1.data, referenceData); QCOMPARE(reader2.data, referenceData); } -#endif void tst_QNetworkReply::ioGetFromHttp() { @@ -4199,26 +4203,28 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" << QNetworkReply::NoError; -#if QT_CONFIG(ftp) - // FTP request with FTP caching proxy - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); - QTest::newRow("ftp-on-ftp") - << proxyList << proxyList.at(0) - << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::NoError; + if (ftpSupported) { + // FTP request with FTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, + QtNetworkSettings::ftpProxyServerName(), 2121); + QTest::newRow("ftp-on-ftp") + << proxyList << proxyList.at(0) + << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; - // The following test doesn't work because QFtp is too limited - // It can only talk to its own kind of proxies + // The following test doesn't work because QFtp is too limited + // It can only talk to its own kind of proxies - // FTP request with SOCKSv5 transparent proxy - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081); - QTest::newRow("ftp-on-socks") - << proxyList << proxyList.at(0) - << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::NoError; -#endif + // FTP request with SOCKSv5 transparent proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, + QtNetworkSettings::socksProxyServerName(), 1081); + QTest::newRow("ftp-on-socks") + << proxyList << proxyList.at(0) + << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + } #ifndef QT_NO_SSL // HTTPS with HTTP transparent proxy @@ -4248,24 +4254,27 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" << QNetworkReply::ProxyNotFoundError; -#if QT_CONFIG(ftp) - // FTP request with HTTP caching proxy - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129); - QTest::newRow("ftp-on-http") - << proxyList << QNetworkProxy() - << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::ProxyNotFoundError; + if (ftpSupported) { + // FTP request with HTTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, + QtNetworkSettings::httpProxyServerName(), 3129); + QTest::newRow("ftp-on-http") + << proxyList << QNetworkProxy() + << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; - // FTP request with HTTP caching proxies - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) - << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3130); - QTest::newRow("ftp-on-multiple-http") - << proxyList << QNetworkProxy() - << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::ProxyNotFoundError; -#endif + // FTP request with HTTP caching proxies + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, + QtNetworkSettings::httpProxyServerName(), 3129) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, + QtNetworkSettings::httpProxyServerName(), 3130); + QTest::newRow("ftp-on-multiple-http") + << proxyList << QNetworkProxy() + << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; + } #ifndef QT_NO_SSL // HTTPS with HTTP caching proxy @@ -4333,16 +4342,18 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" << QNetworkReply::NoError; -#if QT_CONFIG(ftp) - // FTP request with HTTP Caching + FTP - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) - << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); - QTest::newRow("ftp-on-http+ftp") - << proxyList << proxyList.at(1) // second proxy should be used - << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::NoError; -#endif + if (ftpSupported) { + // FTP request with HTTP Caching + FTP + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, + QtNetworkSettings::httpProxyServerName(), 3129) + << QNetworkProxy(QNetworkProxy::FtpCachingProxy, + QtNetworkSettings::ftpProxyServerName(), 2121); + QTest::newRow("ftp-on-http+ftp") + << proxyList << proxyList.at(1) // second proxy should be used + << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + } #ifndef QT_NO_SSL // HTTPS request with HTTP Caching + HTTP transparent @@ -4403,9 +4414,7 @@ void tst_QNetworkReply::ioGetWithManyProxies() #endif QFETCH(QNetworkReply::NetworkError, expectedError); -#if QT_CONFIG(ftp) QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort); -#endif QCOMPARE(reply->error(), expectedError); // Verify that the factory was called properly @@ -4421,10 +4430,8 @@ void tst_QNetworkReply::ioGetWithManyProxies() if (proxyUsed.type() == QNetworkProxy::NoProxy) { QCOMPARE(authspy.count(), 0); } else { -#if QT_CONFIG(ftp) if (QByteArray(QTest::currentDataTag()).startsWith("ftp-")) return; // No authentication with current FTP or with FTP proxies -#endif QCOMPARE(authspy.count(), 1); QCOMPARE(qvariant_cast(authspy.at(0).at(0)), proxyUsed); } @@ -4605,9 +4612,10 @@ void tst_QNetworkReply::ioPutToFileFromProcess() #endif // QT_CONFIG(process) } -#if QT_CONFIG(ftp) void tst_QNetworkReply::ioPutToFtpFromFile_data() { + if (!ftpSupported) + QSKIP("FTP is not supported"); ioPutToFileFromFile_data(); } @@ -4654,7 +4662,6 @@ void tst_QNetworkReply::ioPutToFtpFromFile() QTestEventLoop::instance().enterLoop(10); QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); } -#endif void tst_QNetworkReply::ioPutToHttpFromFile_data() { @@ -8032,9 +8039,10 @@ void tst_QNetworkReply::closeDuringDownload_data() { QTest::addColumn("url"); QTest::newRow("http") << QUrl("http://" + QtNetworkSettings::httpServerName() + "/bigfile"); -#if QT_CONFIG(ftp) - QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/bigfile"); -#endif + if (ftpSupported) { + QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::ftpServerName() + + "/qtest/bigfile"); + } } void tst_QNetworkReply::closeDuringDownload() @@ -8052,9 +8060,10 @@ void tst_QNetworkReply::closeDuringDownload() QVERIFY(destroySpy.wait()); } -#if QT_CONFIG(ftp) void tst_QNetworkReply::ftpAuthentication_data() { + if (!ftpSupported) + QSKIP("FTP is not supported"); QTest::addColumn("referenceName"); QTest::addColumn("url"); QTest::addColumn("error"); @@ -8079,7 +8088,6 @@ void tst_QNetworkReply::ftpAuthentication() QCOMPARE(reply->url(), request.url()); QCOMPARE(reply->error(), QNetworkReply::NetworkError(error)); } -#endif void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890 { @@ -9056,9 +9064,8 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute_data() QTest::newRow("http") << QUrl("http://QInvalidDomain.qt/test"); QTest::newRow("https") << QUrl("https://QInvalidDomain.qt/test"); -#if QT_CONFIG(ftp) - QTest::newRow("ftp") << QUrl("ftp://QInvalidDomain.qt/test"); -#endif + if (ftpSupported) + QTest::newRow("ftp") << QUrl("ftp://QInvalidDomain.qt/test"); QTest::newRow("file") << QUrl("file:///thisfolderdoesn'texist/probably.txt"); #ifdef Q_OS_WIN // Only supported on windows.