File indexing completed on 2024-05-12 03:56:45
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org> 0004 SPDX-FileCopyrightText: 2019-2021 Harald Sitter <sitter@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #ifndef KDELIBS_FTP_H 0010 #define KDELIBS_FTP_H 0011 0012 #include <qplatformdefs.h> 0013 0014 #include <QDateTime> 0015 #include <QUrl> 0016 0017 #include <workerbase.h> 0018 0019 class QTcpServer; 0020 class QTcpSocket; 0021 class QNetworkProxy; 0022 class QAuthenticator; 0023 0024 struct FtpEntry { 0025 QString name; 0026 QString owner; 0027 QString group; 0028 QString link; 0029 0030 KIO::filesize_t size; 0031 mode_t type; 0032 mode_t access; 0033 QDateTime date; 0034 }; 0035 0036 class FtpInternal; 0037 0038 /** 0039 * Login Mode for ftpOpenConnection 0040 */ 0041 enum class LoginMode { 0042 Deferred, 0043 Explicit, 0044 Implicit, 0045 }; 0046 0047 using Result = KIO::WorkerResult; 0048 0049 /** 0050 * Special Result composite for errors during connection. 0051 */ 0052 struct ConnectionResult { 0053 QTcpSocket *socket; 0054 Result result; 0055 }; 0056 0057 QDebug operator<<(QDebug dbg, const Result &r); 0058 0059 //=============================================================================== 0060 // Ftp 0061 // The API class. This class should not contain *any* FTP logic. It acts 0062 // as a container for FtpInternal to prevent the latter from directly doing 0063 // state manipulation via error/finished/opened etc. 0064 //=============================================================================== 0065 class Ftp : public KIO::WorkerBase 0066 { 0067 public: 0068 Ftp(const QByteArray &pool, const QByteArray &app); 0069 ~Ftp() override; 0070 0071 void setHost(const QString &host, quint16 port, const QString &user, const QString &pass) override; 0072 0073 /** 0074 * Connects to a ftp server and logs us in 0075 * m_bLoggedOn is set to true if logging on was successful. 0076 * It is set to false if the connection becomes closed. 0077 * 0078 */ 0079 KIO::WorkerResult openConnection() override; 0080 0081 /** 0082 * Closes the connection 0083 */ 0084 void closeConnection() override; 0085 0086 KIO::WorkerResult stat(const QUrl &url) override; 0087 0088 KIO::WorkerResult listDir(const QUrl &url) override; 0089 KIO::WorkerResult mkdir(const QUrl &url, int permissions) override; 0090 KIO::WorkerResult rename(const QUrl &src, const QUrl &dst, KIO::JobFlags flags) override; 0091 KIO::WorkerResult del(const QUrl &url, bool isfile) override; 0092 KIO::WorkerResult chmod(const QUrl &url, int permissions) override; 0093 0094 KIO::WorkerResult get(const QUrl &url) override; 0095 KIO::WorkerResult put(const QUrl &url, int permissions, KIO::JobFlags flags) override; 0096 0097 void worker_status() override; 0098 0099 /** 0100 * Handles the case that one side of the job is a local file 0101 */ 0102 KIO::WorkerResult copy(const QUrl &src, const QUrl &dest, int permissions, KIO::JobFlags flags) override; 0103 0104 std::unique_ptr<FtpInternal> d; 0105 }; 0106 0107 /** 0108 * Internal logic class. 0109 * 0110 * This class implements strict separation between the API (Ftp) and 0111 * the logic behind the API (FtpInternal). This class' functions 0112 * are meant to return Result objects up the call stack to Ftp where 0113 * they will be turned into command results (e.g. error(), 0114 * finished(), etc.). This class cannot and must not call these signals 0115 * directly as it leads to unclear states. 0116 */ 0117 class FtpInternal : public QObject 0118 { 0119 Q_OBJECT 0120 public: 0121 explicit FtpInternal(Ftp *qptr); 0122 ~FtpInternal() override; 0123 0124 // ---------------------------------------- API 0125 0126 void setHost(const QString &host, quint16 port, const QString &user, const QString &pass); 0127 0128 /** 0129 * Connects to a ftp server and logs us in 0130 * m_bLoggedOn is set to true if logging on was successful. 0131 * It is set to false if the connection becomes closed. 0132 * 0133 */ 0134 Q_REQUIRED_RESULT Result openConnection(); 0135 0136 /** 0137 * Closes the connection 0138 */ 0139 void closeConnection(); 0140 0141 Q_REQUIRED_RESULT Result stat(const QUrl &url); 0142 0143 Result listDir(const QUrl &url); 0144 Q_REQUIRED_RESULT Result mkdir(const QUrl &url, int permissions); 0145 Q_REQUIRED_RESULT Result rename(const QUrl &src, const QUrl &dst, KIO::JobFlags flags); 0146 Q_REQUIRED_RESULT Result del(const QUrl &url, bool isfile); 0147 Q_REQUIRED_RESULT Result chmod(const QUrl &url, int permissions); 0148 0149 Q_REQUIRED_RESULT Result get(const QUrl &url); 0150 Q_REQUIRED_RESULT Result put(const QUrl &url, int permissions, KIO::JobFlags flags); 0151 // virtual void mimetype( const QUrl& url ); 0152 0153 void worker_status(); 0154 0155 /** 0156 * Handles the case that one side of the job is a local file 0157 */ 0158 Q_REQUIRED_RESULT Result copy(const QUrl &src, const QUrl &dest, int permissions, KIO::JobFlags flags); 0159 0160 // ---------------------------------------- END API 0161 0162 static bool isSocksProxyScheme(const QString &scheme); 0163 bool isSocksProxy() const; 0164 0165 /** 0166 * Connect and login to the FTP server. 0167 * 0168 * @param loginMode controls if login info should be sent<br> 0169 * loginDeferred - must not be logged on, no login info is sent<br> 0170 * loginExplicit - must not be logged on, login info is sent<br> 0171 * loginImplicit - login info is sent if not logged on 0172 * 0173 * @return true on success (a login failure would return false). 0174 */ 0175 Q_REQUIRED_RESULT Result ftpOpenConnection(LoginMode loginMode); 0176 0177 /** 0178 * Called by openConnection. It logs us in. 0179 * m_initialPath is set to the current working directory 0180 * if logging on was successful. 0181 * 0182 * @param userChanged if not nullptr, will be set to true if the user name 0183 * was changed during login. 0184 * @return true on success. 0185 */ 0186 Q_REQUIRED_RESULT Result ftpLogin(bool *userChanged = nullptr); 0187 0188 /** 0189 * ftpSendCmd - send a command (@p cmd) and read response 0190 * 0191 * @param maxretries number of time it should retry. Since it recursively 0192 * calls itself if it can't read the answer (this happens especially after 0193 * timeouts), we need to limit the recursiveness ;-) 0194 * 0195 * return true if any response received, false on error 0196 */ 0197 Q_REQUIRED_RESULT bool ftpSendCmd(const QByteArray &cmd, int maxretries = 1); 0198 0199 /** 0200 * Use the SIZE command to get the file size. 0201 * @param mode the size depends on the transfer mode, hence this arg. 0202 * @return true on success 0203 * Gets the size into m_size. 0204 */ 0205 bool ftpSize(const QString &path, char mode); 0206 0207 /** 0208 * Returns true if the file exists. 0209 * Implemented using the SIZE command. 0210 */ 0211 bool ftpFileExists(const QString &path); 0212 0213 /** 0214 * Set the current working directory, but only if not yet current 0215 */ 0216 Q_REQUIRED_RESULT bool ftpFolder(const QString &path); 0217 0218 /** 0219 * Runs a command on the ftp server like "list" or "retr". In contrast to 0220 * ftpSendCmd a data connection is opened. The corresponding socket 0221 * sData is available for reading/writing on success. 0222 * The connection must be closed afterwards with ftpCloseCommand. 0223 * 0224 * @param mode is 'A' or 'I'. 'A' means ASCII transfer, 'I' means binary transfer. 0225 * @param errorcode the command-dependent error code to emit on error 0226 * 0227 * @return true if the command was accepted by the server. 0228 */ 0229 Q_REQUIRED_RESULT Result ftpOpenCommand(const char *command, const QString &path, char mode, int errorcode, KIO::fileoffset_t offset = 0); 0230 0231 /** 0232 * The counterpart to openCommand. 0233 * Closes data sockets and then reads line sent by server at 0234 * end of command. 0235 * @return false on error (line doesn't start with '2') 0236 */ 0237 bool ftpCloseCommand(); 0238 0239 /** 0240 * Send "TYPE I" or "TYPE A" only if required, see m_cDataMode. 0241 * 0242 * Use 'A' to select ASCII and 'I' to select BINARY mode. If 0243 * cMode is '?' the m_bTextMode flag is used to choose a mode. 0244 */ 0245 bool ftpDataMode(char cMode); 0246 0247 // void ftpAbortTransfer(); 0248 0249 /** 0250 * Used by ftpOpenCommand, return 0 on success or an error code 0251 */ 0252 int ftpOpenDataConnection(); 0253 0254 /** 0255 * closes a data connection, see ftpOpenDataConnection() 0256 */ 0257 void ftpCloseDataConnection(); 0258 0259 /** 0260 * Helper for ftpOpenDataConnection 0261 */ 0262 int ftpOpenPASVDataConnection(); 0263 /** 0264 * Helper for ftpOpenDataConnection 0265 */ 0266 int ftpOpenEPSVDataConnection(); 0267 /** 0268 * Helper for ftpOpenDataConnection 0269 */ 0270 int ftpOpenPortDataConnection(); 0271 0272 bool ftpChmod(const QString &path, int permissions); 0273 0274 // used by listDir 0275 Q_REQUIRED_RESULT Result ftpOpenDir(const QString &path); 0276 /** 0277 * Called to parse directory listings, call this until it returns false 0278 */ 0279 bool ftpReadDir(FtpEntry &ftpEnt); 0280 0281 /** 0282 * Helper to fill an UDSEntry 0283 */ 0284 void ftpCreateUDSEntry(const QString &filename, const FtpEntry &ftpEnt, KIO::UDSEntry &entry, bool isDir); 0285 0286 void ftpShortStatAnswer(const QString &filename, bool isDir); 0287 0288 Q_REQUIRED_RESULT Result ftpStatAnswerNotFound(const QString &path, const QString &filename); 0289 0290 /** 0291 * This is the internal implementation of rename() - set put(). 0292 * 0293 * @return true on success. 0294 */ 0295 Q_REQUIRED_RESULT Result ftpRename(const QString &src, const QString &dst, KIO::JobFlags flags); 0296 0297 /** 0298 * Called by openConnection. It opens the control connection to the ftp server. 0299 * 0300 * @return true on success. 0301 */ 0302 Q_REQUIRED_RESULT Result ftpOpenControlConnection(); 0303 Q_REQUIRED_RESULT Result ftpOpenControlConnection(const QString &host, int port); 0304 0305 /** 0306 * closes the socket holding the control connection (see ftpOpenControlConnection) 0307 */ 0308 void ftpCloseControlConnection(); 0309 0310 /** 0311 * read a response from the server (a trailing CR gets stripped) 0312 * @param iOffset -1 to read a new line from the server<br> 0313 * 0 to return the whole response string 0314 * >0 to return the response with iOffset chars skipped 0315 * @return the response message with iOffset chars skipped (or "" if iOffset points 0316 * behind the available data) 0317 */ 0318 const char *ftpResponse(int iOffset); 0319 0320 /** 0321 * This is the internal implementation of get() - see copy(). 0322 * 0323 * IMPORTANT: the caller should call ftpCloseCommand() on return. 0324 * The function does not call error(), the caller should do this. 0325 * 0326 * @param iError set to an ERR_xxxx code on error 0327 * @param iCopyFile -1 -or- handle of a local destination file 0328 * @param hCopyOffset local file only: non-zero for resume 0329 * @return 0 for success, -1 for server error, -2 for client error 0330 */ 0331 Q_REQUIRED_RESULT Result ftpGet(int iCopyFile, const QString &sCopyFile, const QUrl &url, KIO::fileoffset_t hCopyOffset); 0332 0333 /** 0334 * This is the internal implementation of put() - see copy(). 0335 * 0336 * IMPORTANT: the caller should call ftpCloseCommand() on return. 0337 * The function does not call error(), the caller should do this. 0338 * 0339 * @param iError set to an ERR_xxxx code on error 0340 * @param iCopyFile -1 -or- handle of a local source file 0341 * @return 0 for success, -1 for server error, -2 for client error 0342 */ 0343 Q_REQUIRED_RESULT Result ftpPut(int iCopyFile, const QUrl &url, int permissions, KIO::JobFlags flags); 0344 0345 /** 0346 * helper called from copy() to implement FILE -> FTP transfers 0347 * 0348 * @param iError set to an ERR_xxxx code on error 0349 * @param iCopyFile [out] handle of a local source file 0350 * @param sCopyFile path of the local source file 0351 * @return 0 for success, -1 for server error, -2 for client error 0352 */ 0353 Q_REQUIRED_RESULT Result ftpCopyPut(int &iCopyFile, const QString &sCopyFile, const QUrl &url, int permissions, KIO::JobFlags flags); 0354 0355 /** 0356 * helper called from copy() to implement FTP -> FILE transfers 0357 * 0358 * @param iError set to an ERR_xxxx code on error 0359 * @param iCopyFile [out] handle of a local source file 0360 * @param sCopyFile path of the local destination file 0361 * @return 0 for success, -1 for server error, -2 for client error 0362 */ 0363 Q_REQUIRED_RESULT Result ftpCopyGet(int &iCopyFile, const QString &sCopyFile, const QUrl &url, int permissions, KIO::JobFlags flags); 0364 0365 /** 0366 * Sends the MIME type of the content to retrieved. 0367 * 0368 * @param iError set to an ERR_xxxx code on error 0369 * @return 0 for success, -1 for server error, -2 for client error 0370 */ 0371 Q_REQUIRED_RESULT Result ftpSendMimeType(const QUrl &url); 0372 0373 /** 0374 * Fixes up an entry name so that extraneous whitespaces do not cause 0375 * problems. See bug# 88575 and bug# 300988. 0376 */ 0377 void fixupEntryName(FtpEntry *ftpEnt); 0378 0379 /** 0380 * Calls @ref statEntry. 0381 */ 0382 bool maybeEmitStatEntry(FtpEntry &ftpEnt, const QString &filename, bool isDir); 0383 0384 /** 0385 * Setup the connection to the server. 0386 */ 0387 Q_REQUIRED_RESULT ConnectionResult synchronousConnectToHost(const QString &host, quint16 port); 0388 0389 private: // data members 0390 Ftp *const q; 0391 0392 QString m_host; 0393 int m_port = 0; 0394 QString m_user; 0395 QString m_pass; 0396 /** 0397 * Where we end up after connecting 0398 */ 0399 QString m_initialPath; 0400 QUrl m_proxyURL; 0401 QStringList m_proxyUrls; 0402 0403 /** 0404 * the current working directory - see ftpFolder 0405 */ 0406 QString m_currentPath; 0407 0408 /** 0409 * the status returned by the FTP protocol, set in ftpResponse() 0410 */ 0411 int m_iRespCode = 0; 0412 0413 /** 0414 * the status/100 returned by the FTP protocol, set in ftpResponse() 0415 */ 0416 int m_iRespType = 0; 0417 0418 /** 0419 * This flag is maintained by ftpDataMode() and contains I or A after 0420 * ftpDataMode() has successfully set the mode. 0421 */ 0422 char m_cDataMode; 0423 0424 /** 0425 * true if logged on (m_control should also be non-nullptr) 0426 */ 0427 bool m_bLoggedOn; 0428 0429 /** 0430 * true if a "textmode" metadata key was found by ftpLogin(). This 0431 * switches the ftp data transfer mode from binary to ASCII. 0432 */ 0433 bool m_bTextMode; 0434 0435 /** 0436 * true if a data stream is open, used in closeConnection(). 0437 * 0438 * When the user cancels a get or put command the Ftp dtor will be called, 0439 * which in turn calls closeConnection(). The later would try to send QUIT 0440 * which won't work until timeout. ftpOpenCommand sets the m_bBusy flag so 0441 * that the sockets will be closed immediately - the server should be 0442 * capable of handling this and return an error code on thru the control 0443 * connection. The m_bBusy gets cleared by the ftpCloseCommand() routine. 0444 */ 0445 bool m_bBusy; 0446 0447 bool m_bPasv; 0448 0449 KIO::filesize_t m_size; 0450 static const KIO::filesize_t UnknownSize; 0451 0452 enum { 0453 epsvUnknown = 0x01, 0454 epsvAllUnknown = 0x02, 0455 eprtUnknown = 0x04, 0456 epsvAllSent = 0x10, 0457 pasvUnknown = 0x20, 0458 chmodUnknown = 0x100, 0459 }; 0460 int m_extControl; 0461 0462 /** 0463 * control connection socket, only set if openControl() succeeded 0464 */ 0465 QTcpSocket *m_control = nullptr; 0466 QByteArray m_lastControlLine; 0467 0468 /** 0469 * data connection socket 0470 */ 0471 QTcpSocket *m_data = nullptr; 0472 0473 /** 0474 * active mode server socket 0475 */ 0476 QTcpServer *m_server = nullptr; 0477 }; 0478 0479 #endif // KDELIBS_FTP_H