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