QFtpCompat 1.0.0
Qt6-compatible async FTP client library
Loading...
Searching...
No Matches
qftpcompat.h
Go to the documentation of this file.
1
5
6// SPDX-License-Identifier: MIT
7
8#pragma once
9
10#include "qftpcompatdirentry.h"
11
12#include <QAbstractSocket>
13#include <QObject>
14#include <QQueue>
15#include <QSslConfiguration>
16#include <QSslError>
17#include <QSslSocket>
18#include <QUrl>
19
20class QIODevice;
21class QByteArray;
22
23namespace QFtpCompatInternal { struct Command; }
24
69class QFtpCompat : public QObject
70{
71 Q_OBJECT
72
73public:
74 // -----------------------------------------------------------------
75 // Enumerations
76 // -----------------------------------------------------------------
77
88 Q_ENUM(State)
89
90
114 Q_ENUM(Error)
115
116
121 enum class TransferMode {
124 };
125 Q_ENUM(TransferMode)
126
127
137 enum class TransferType {
140 };
141 Q_ENUM(TransferType)
142
143
149 enum class EncryptionMode {
150 None,
151 Explicit,
152 Implicit,
153 };
154 Q_ENUM(EncryptionMode)
155
156 // -----------------------------------------------------------------
157 // Construction
158 // -----------------------------------------------------------------
159
160 explicit QFtpCompat(QObject *parent = nullptr);
161 ~QFtpCompat() override;
162
163 // -----------------------------------------------------------------
164 // Connection commands
165 // -----------------------------------------------------------------
166
199 int open(const QUrl &url,
200 EncryptionMode mode = EncryptionMode::None);
201
208 void close();
209
216 void abort();
217
218 // -----------------------------------------------------------------
219 // Transfer commands
220 // -----------------------------------------------------------------
221
230 int get(const QUrl &url, QIODevice *dst,
232
241 int get(const QUrl &url, QByteArray *dst,
243
252 int put(const QUrl &url, const QByteArray &data,
254
267 int put(const QUrl &url, QIODevice *src,
269
270 // -----------------------------------------------------------------
271 // Directory / file-management commands
272 // -----------------------------------------------------------------
273
284 int list(const QUrl &url);
285
291 int mkdir(const QUrl &url);
292
298 int rmdir(const QUrl &url);
299
305 int remove(const QUrl &url);
306
314 int rename(const QUrl &from, const QUrl &to);
315
321 int cd(const QUrl &url);
322
329 int pwd();
330
338 int rawCommand(const QString &command);
339
340 // -----------------------------------------------------------------
341 // State queries
342 // -----------------------------------------------------------------
343
345 [[nodiscard]] State state() const noexcept;
347 [[nodiscard]] Error error() const noexcept;
349 [[nodiscard]] QString errorString() const noexcept;
351 [[nodiscard]] int currentId() const noexcept;
353 [[nodiscard]] bool hasPendingCommands() const noexcept;
354
360 // -----------------------------------------------------------------
361 // TLS / SSL
362 // -----------------------------------------------------------------
363
377 void setSslConfiguration(const QSslConfiguration &config);
378
380 [[nodiscard]] QSslConfiguration sslConfiguration() const;
381
384 void ignoreSslErrors();
385
386 void clearPendingCommands();
387
390 void resetConnection();
391
392signals:
397 void stateChanged(QFtpCompat::State newState);
398
403 void commandStarted(int id);
404
411 void commandFinished(int id, bool error);
412
417 void done(bool error);
418
424
430 void dataTransferProgress(qint64 bytesTransferred, qint64 bytesTotal);
431
437 void rawCommandReply(int code, QString detail);
438
447 void sslErrors(const QList<QSslError> &errors);
448
449private slots:
450 void onControlConnected();
451 void onControlReadyRead();
452 void onControlError(QAbstractSocket::SocketError socketError);
453
454 void onDataConnected();
455 void onDataReadyRead();
456 void onDataDisconnected();
457 void onDataError(QAbstractSocket::SocketError socketError);
458 void onTransferCompleted();
459
460private:
461 // -----------------------------------------------------------------
462 // Internal state machine
463 // -----------------------------------------------------------------
464 enum class ControlState {
465 Idle,
466 WaitingForWelcome,
467 WaitingForUserAck,
468 WaitingForPassAck,
469 WaitingForTypeAck,
470 WaitingForPasvAck,
471 ConnectingData,
472 WaitingForTransferStartAck,
473 Transferring,
474 WaitingForTransferCompleteAck,
475 WaitingForSimpleAck,
476 WaitingForRnfrAck,
477 WaitingForRntoAck,
478 WaitingForAbortAck,
479 WaitingForQuitAck,
480 // TLS-specific states
481 WaitingForAuthTlsAck,
482 WaitingForPbszAck,
483 WaitingForProtAck,
484 WaitingForControlHandshake,
485 WaitingForDataHandshake,
486 };
487
488 // -----------------------------------------------------------------
489 // Command queue management
490 // -----------------------------------------------------------------
491 int enqueue(QFtpCompatInternal::Command *cmd);
492 void startNextCommand();
493 void startCurrentCommand();
494
495 void finalizeCommand(bool hadError);
496
497 // -----------------------------------------------------------------
498 // FTP protocol helpers
499 // -----------------------------------------------------------------
500 void sendCommand(const QByteArray &cmd);
501 void processResponse(int code, const QByteArray &message);
502
503 void beginDataTransfer();
504 void sendTypeCommand();
505 void sendPasv();
506 void sendDataTransferCommand();
507 void startDataChannelEncryption();
508
509 [[nodiscard]] bool parsePasvAddress(const QByteArray &msg,
510 QString &host, quint16 &port) const;
511
512 void setError(Error err, const QString &detail);
513 void setState(State s);
514
515 [[nodiscard]] bool isDataTransferCommand() const noexcept;
516
517 // -----------------------------------------------------------------
518 // Data
519 // -----------------------------------------------------------------
520 QSslSocket *m_control{nullptr};
521 QSslSocket *m_data{nullptr};
522
523 EncryptionMode m_encMode{EncryptionMode::None};
524 QSslConfiguration m_sslConfig{QSslConfiguration::defaultConfiguration()};
525
526 QByteArray m_dataReadBuf;
527
528 State m_state{State::Unconnected};
529 ControlState m_ctrlState{ControlState::Idle};
530 Error m_error{Error::NoError};
531 QString m_errorString;
532
533 QString m_host;
534 quint16 m_port{21};
535
536 // Current command
537 QFtpCompatInternal::Command *m_current{nullptr};
538 QQueue<QFtpCompatInternal::Command *> m_queue;
539
540 int m_nextId{0};
541
542 // Data-channel completion flags (see DownloadManager design notes)
543 bool m_dataChannelClosed{false};
544 bool m_ctrlTransferComplete{false};
545
546 bool m_abortPending{false};
547
548 qint64 m_downloadReceived{0};
549 qint64 m_uploadTotal{0};
550 qint64 m_uploadTransferred{0};
551};
Represents a single entry from an FTP LIST response.
Asynchronous FTP client for Qt6.
Definition qftpcompat.h:70
int currentId() const noexcept
ID of the command currently being executed, or -1 if idle.
int remove(const QUrl &url)
Deletes a file on the server (DELE).
void abort()
Aborts the current data transfer and clears the command queue.
State state() const noexcept
Current connection state.
void done(bool error)
Emitted when all queued commands have completed.
int pwd()
Requests the current working directory path (PWD).
int open(const QUrl &url, EncryptionMode mode=EncryptionMode::None)
Connects to the FTP server and logs in using the URL credentials.
TransferMode
FTP data channel mode.
Definition qftpcompat.h:121
@ Active
PORT – server opens the data connection (not implemented).
Definition qftpcompat.h:123
@ Passive
PASV – client opens the data connection (firewall-friendly).
Definition qftpcompat.h:122
int rmdir(const QUrl &url)
Removes an empty directory on the server (RMD).
int put(const QUrl &url, const QByteArray &data, TransferType type=TransferType::Binary)
Uploads data to the remote path in url.
int rawCommand(const QString &command)
Sends an arbitrary FTP command on the control channel.
void stateChanged(QFtpCompat::State newState)
Emitted when the connection state changes.
int cd(const QUrl &url)
Changes the current working directory (CWD).
void rawCommandReply(int code, QString detail)
Emitted for rawCommand() responses and pwd() results.
EncryptionMode
FTP encryption mode. \value None Plain FTP – default, fully backward-compatible. \value Explicit Expl...
Definition qftpcompat.h:149
void ignoreSslErrors()
int mkdir(const QUrl &url)
Creates a directory on the server (MKD).
void commandStarted(int id)
Emitted when a queued command begins executing.
int list(const QUrl &url)
Requests a directory listing (LIST).
Error
Error codes set on the most recent failed command.
Definition qftpcompat.h:93
@ TlsHandshakeFailed
TLS handshake failed on control or data channel.
Definition qftpcompat.h:111
@ FileNotFound
Server returned 550 for a file operation.
Definition qftpcompat.h:102
@ NotConnected
Command issued without an active connection.
Definition qftpcompat.h:99
@ NetworkError
Generic socket error.
Definition qftpcompat.h:98
@ PermissionDenied
Server returned 553 / 550 permission error.
Definition qftpcompat.h:103
@ LoginFailed
USER/PASS rejected by the server.
Definition qftpcompat.h:101
@ NotLoggedIn
Command requires authentication.
Definition qftpcompat.h:100
@ NoError
No error since the last successful command.
Definition qftpcompat.h:94
@ Aborted
Operation cancelled by abort().
Definition qftpcompat.h:107
@ ServerError
Unexpected server response code.
Definition qftpcompat.h:104
@ LocalFileError
Could not open or write to the local file/device.
Definition qftpcompat.h:106
@ ConnectionRefused
Server actively refused the TCP connection.
Definition qftpcompat.h:96
@ UnknownError
Catch-all for unclassified errors.
Definition qftpcompat.h:109
@ TransferFailed
Data channel closed before transfer completed.
Definition qftpcompat.h:108
@ ParseError
Failed to parse a server response (PASV, LIST).
Definition qftpcompat.h:105
@ AuthTlsRejected
Server rejected the AUTH TLS command.
Definition qftpcompat.h:112
@ NetworkTimeout
No activity within the inactivity timeout.
Definition qftpcompat.h:97
@ HostNotFound
DNS resolution failed.
Definition qftpcompat.h:95
void listInfo(QFtpCompatDirEntry entry)
Emitted once per entry during a list() command.
void close()
Sends QUIT and closes the connection gracefully.
int rename(const QUrl &from, const QUrl &to)
Renames or moves a file on the server (RNFR + RNTO).
void setSslConfiguration(const QSslConfiguration &config)
Removes all pending (not yet started) commands from the queue.
Error error() const noexcept
Error code set by the most recent failed command.
void commandFinished(int id, bool error)
Emitted when a command completes (successfully or with error).
int get(const QUrl &url, QIODevice *dst, TransferType type=TransferType::Binary)
Downloads a remote file into dst.
void resetConnection()
void sslErrors(const QList< QSslError > &errors)
Emitted when SSL/TLS errors occur.
State
High-level connection state.
Definition qftpcompat.h:81
@ Unconnected
No TCP connection established.
Definition qftpcompat.h:82
@ Connected
TCP connected, waiting for server greeting (220).
Definition qftpcompat.h:84
@ Closing
QUIT sent, waiting for server acknowledgement.
Definition qftpcompat.h:86
@ Connecting
TCP connect in progress.
Definition qftpcompat.h:83
@ LoggedIn
Authenticated; ready to accept commands.
Definition qftpcompat.h:85
QSslConfiguration sslConfiguration() const
Returns the current SSL configuration.
bool hasPendingCommands() const noexcept
true if commands are waiting in the queue.
QString errorString() const noexcept
Verbose, human-readable description of the last error.
TransferType
FTP data representation type (RFC 959 §3.1.1).
Definition qftpcompat.h:137
@ Binary
TYPE I – raw binary (8-bit) transfer. Fully implemented.
Definition qftpcompat.h:138
@ Ascii
TYPE A – text transfer. Protocol-level TYPE sent; no CRLF transform (TODO).
Definition qftpcompat.h:139
void dataTransferProgress(qint64 bytesTransferred, qint64 bytesTotal)
Emitted periodically during data transfers.
FTP directory entry returned by QFtpCompat::list().