diff options
author | Mårten Nordheim <marten.nordheim@qt.io> | 2020-08-20 12:03:54 +0200 |
---|---|---|
committer | Mårten Nordheim <marten.nordheim@qt.io> | 2020-08-27 18:58:21 +0200 |
commit | f7f79483e73fed5664763a125b3d27861586b7d2 (patch) | |
tree | 13910131de10d3d8d6d240b4cfd05309de8343c8 /src | |
parent | 3964ece5a566d1ed517406f0ff713f6f184628ae (diff) | |
download | qtbase-f7f79483e73fed5664763a125b3d27861586b7d2.tar.gz |
Remove QFtp sources etc. in favor of alternate distribution
While we initially wanted to just disable the functionality the way it
is currently built forces people to do a full build of Qt just to enable
it. Instead of doing this half-measure let's just remove the code
completely from QtBase and rather prepare QtNetwork to handle being a
plugin that can be compiled at any time.
Task-number: QTBUG-80340
Change-Id: I19155c8c167cf932088f01b2a9706d0e7ab792d1
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/network/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/network/access/access.pri | 10 | ||||
-rw-r--r-- | src/network/access/qftp.cpp | 2456 | ||||
-rw-r--r-- | src/network/access/qftp_p.h | 176 | ||||
-rw-r--r-- | src/network/access/qnetworkaccesscachebackend.cpp | 3 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessfilebackend.cpp | 3 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessftpbackend.cpp | 436 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessftpbackend_p.h | 126 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 10 | ||||
-rw-r--r-- | src/network/configure.cmake | 8 | ||||
-rw-r--r-- | src/network/configure.json | 9 | ||||
-rw-r--r-- | src/network/doc/snippets/code/src_network_access_qftp.cpp | 109 | ||||
-rw-r--r-- | src/network/doc/src/examples.qdoc | 1 | ||||
-rw-r--r-- | src/network/doc/src/network-programming.qdoc | 4 | ||||
-rw-r--r-- | src/network/kernel/kernel.pri | 5 | ||||
-rw-r--r-- | src/network/kernel/qurlinfo.cpp | 727 | ||||
-rw-r--r-- | src/network/kernel/qurlinfo_p.h | 133 |
17 files changed, 2 insertions, 4221 deletions
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 <DIR> 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("<DIR>")) { - 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+" - "(<DIR>|\\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]<lowerLimit[i] || 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<signed char>(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 <private/qobject_p.h> -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<QFtpCommand *> 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 <QtNetwork/private/qtnetworkglobal_p.h> -#include <QtCore/qstring.h> -#include <private/qurlinfo_p.h> -#include <QtCore/qobject.h> - -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 <QStringList> - -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<QNetworkAccessCachedFtpConnection *>(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 <QtNetwork/private/qtnetworkglobal_p.h> -#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<QNetworkAccessCachedFtpConnection> 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 <limits.h> - -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 <QtNetwork/private/qtnetworkglobal_p.h> -#include <QtCore/qdatetime.h> -#include <QtCore/qstring.h> -#include <QtCore/qiodevice.h> - -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 |