1 #ifndef FILEZILLA_ENGINE_COMMANDS_HEADER 2 #define FILEZILLA_ENGINE_COMMANDS_HEADER 3 4 #include "server.h" 5 #include "serverpath.h" 6 #include "reader.h" 7 #include "writer.h" 8 9 #include <libfilezilla/uri.hpp> 10 11 // See below for actual commands and their parameters 12 13 // Command IDs 14 // ----------- 15 enum class Command 16 { 17 none = 0, 18 connect, 19 disconnect, 20 list, 21 transfer, 22 del, 23 removedir, 24 mkdir, 25 rename, 26 chmod, 27 raw, 28 httprequest, // Only used by HTTP protocol 29 30 // Only used internally 31 sleep, 32 lookup, 33 cwd, 34 common_private1, // Internal commands common to multiple protocols 35 common_private2, 36 private1, 37 private2, 38 private3, 39 private4, 40 private5, 41 private6, 42 }; 43 44 // Reply codes 45 // ----------- 46 #define FZ_REPLY_OK (0x0000) 47 #define FZ_REPLY_WOULDBLOCK (0x0001) 48 #define FZ_REPLY_ERROR (0x0002) 49 #define FZ_REPLY_CRITICALERROR (0x0004 | FZ_REPLY_ERROR) // If there is no point to retry an operation, this 50 // code is returned. 51 #define FZ_REPLY_CANCELED (0x0008 | FZ_REPLY_ERROR) 52 #define FZ_REPLY_SYNTAXERROR (0x0010 | FZ_REPLY_ERROR) 53 #define FZ_REPLY_NOTCONNECTED (0x0020 | FZ_REPLY_ERROR) 54 #define FZ_REPLY_DISCONNECTED (0x0040) 55 #define FZ_REPLY_INTERNALERROR (0x0080 | FZ_REPLY_ERROR) // If you get this reply, the error description will be 56 // given by the last debug_warning log message. This 57 // should not happen unless there is a bug in FileZilla 3. 58 #define FZ_REPLY_BUSY (0x0100 | FZ_REPLY_ERROR) 59 #define FZ_REPLY_ALREADYCONNECTED (0x0200 | FZ_REPLY_ERROR) // Will be returned by connect if already connected 60 #define FZ_REPLY_PASSWORDFAILED 0x0400 // Will be returned if PASS fails with 5yz reply code. 61 #define FZ_REPLY_TIMEOUT (0x0800 | FZ_REPLY_ERROR) 62 #define FZ_REPLY_NOTSUPPORTED (0x1000 | FZ_REPLY_ERROR) // Will be returned if command not supported by that protocol 63 #define FZ_REPLY_WRITEFAILED (0x2000 | FZ_REPLY_ERROR) // Happens if local file could not be written during transfer 64 #define FZ_REPLY_LINKNOTDIR (0x4000 | FZ_REPLY_ERROR) 65 66 #define FZ_REPLY_CONTINUE 0x8000 // Used internally 67 #define FZ_REPLY_ERROR_NOTFOUND (0x10000 | FZ_REPLY_ERROR) // Used internally 68 69 // --------------- // 70 // Actual commands // 71 // --------------- // 72 73 class FZC_PUBLIC_SYMBOL CCommand 74 { 75 public: 76 CCommand() = default; 77 virtual ~CCommand() = default; 78 79 virtual Command GetId() const = 0; 80 virtual CCommand *Clone() const = 0; 81 valid()82 virtual bool valid() const { return true; } 83 84 protected: 85 CCommand(CCommand const&) = default; 86 CCommand& operator=(CCommand const&) = default; 87 }; 88 89 template<typename Derived, Command id> 90 class FZC_PUBLIC_SYMBOL CCommandHelper : public CCommand 91 { 92 public: GetId()93 virtual Command GetId() const final { return id; } 94 Clone()95 virtual CCommand* Clone() const final { 96 return new Derived(static_cast<Derived const&>(*this)); 97 } 98 99 protected: 100 CCommandHelper<Derived, id>() = default; 101 CCommandHelper<Derived, id>(CCommandHelper<Derived, id> const&) = default; 102 CCommandHelper<Derived, id>& operator=(CCommandHelper<Derived, id> const&) = default; 103 }; 104 105 template<Command id> 106 class FZC_PUBLIC_SYMBOL CBasicCommand final : public CCommandHelper<CBasicCommand<id>, id> 107 { 108 }; 109 110 class FZC_PUBLIC_SYMBOL CConnectCommand final : public CCommandHelper<CConnectCommand, Command::connect> 111 { 112 public: 113 explicit CConnectCommand(CServer const& server, ServerHandle const& handle, Credentials const& credentials, bool retry_conncting = true); 114 GetServer()115 CServer const& GetServer() const { return server_; } GetHandle()116 ServerHandle const& GetHandle() const { return handle_; } GetCredentials()117 Credentials const& GetCredentials() const { return credentials_; } RetryConnecting()118 bool RetryConnecting() const { return retry_connecting_; } 119 120 virtual bool valid() const override; 121 protected: 122 CServer const server_; 123 ServerHandle const handle_; 124 Credentials const credentials_; 125 bool const retry_connecting_; 126 }; 127 128 typedef CBasicCommand<Command::disconnect> CDisconnectCommand; 129 130 #define LIST_FLAG_REFRESH 1 131 #define LIST_FLAG_AVOID 2 132 #define LIST_FLAG_FALLBACK_CURRENT 4 133 #define LIST_FLAG_LINK 8 134 #define LIST_FLAG_CLEARCACHE 16 135 class FZC_PUBLIC_SYMBOL CListCommand final : public CCommandHelper<CListCommand, Command::list> 136 { 137 // Without a given directory, the current directory will be listed. 138 // Directories can either be given as absolute path or as 139 // pair of an absolute path and the very last path segments. 140 141 // Set LIST_FLAG_REFRESH to get a directory listing even if a cache 142 // lookup can be made after finding out true remote directory. 143 // 144 // Set LIST_FLAG_AVOID to get a directory listing only if cache lookup 145 // fails or contains unsure entries, otherwise don't send listing. 146 // 147 // If LIST_FLAG_FALLBACK_CURRENT is set and CWD fails, list whatever 148 // directory we are currently in. Useful for initial reconnect to the 149 // server when we don't know if remote directory still exists 150 // 151 // LIST_FLAG_LINK is used for symlink discovery. There's unfortunately 152 // no sane way to distinguish between symlinks to files and symlinks to 153 // directories. 154 public: 155 explicit CListCommand(int flags = 0); 156 explicit CListCommand(CServerPath path, std::wstring const& subDir = std::wstring(), int flags = 0); 157 158 CServerPath GetPath() const; 159 std::wstring GetSubDir() const; 160 GetFlags()161 int GetFlags() const { return m_flags; } 162 163 bool valid() const; 164 165 protected: 166 CServerPath const m_path; 167 std::wstring const m_subDir; 168 int const m_flags; 169 }; 170 171 enum class transfer_flags : unsigned short 172 { 173 none = 0, 174 175 interface_reserved_mask = 0x08u, // The engine will never touch these 176 177 download = 0x10, 178 fsync = 0x20, 179 180 // Free bits in the middle 181 182 protocol_reserved_mask = 0xfe00, 183 protocol_reserved_max = 0x8000 184 }; 185 186 inline bool operator&(transfer_flags lhs, transfer_flags rhs) 187 { 188 return (static_cast<std::underlying_type_t<transfer_flags>>(lhs) & static_cast<std::underlying_type_t<transfer_flags>>(rhs)) != 0; 189 } 190 191 inline transfer_flags operator|(transfer_flags lhs, transfer_flags rhs) 192 { 193 return static_cast<transfer_flags>(static_cast<std::underlying_type_t<transfer_flags>>(lhs) | static_cast<std::underlying_type_t<transfer_flags>>(rhs)); 194 } 195 196 inline transfer_flags& operator|=(transfer_flags& lhs, transfer_flags rhs) 197 { 198 lhs = static_cast<transfer_flags>(static_cast<std::underlying_type_t<transfer_flags>>(lhs) | static_cast<std::underlying_type_t<transfer_flags>>(rhs)); 199 return lhs; 200 } 201 202 inline transfer_flags operator-(transfer_flags lhs, transfer_flags rhs) 203 { 204 return static_cast<transfer_flags>(static_cast<std::underlying_type_t<transfer_flags>>(lhs) & ~static_cast<std::underlying_type_t<transfer_flags>>(rhs)); 205 } 206 207 inline transfer_flags& operator-=(transfer_flags& lhs, transfer_flags rhs) 208 { 209 lhs = static_cast<transfer_flags>(static_cast<std::underlying_type_t<transfer_flags>>(lhs) & ~static_cast<std::underlying_type_t<transfer_flags>>(rhs)); 210 return lhs; 211 } 212 213 inline bool operator!(transfer_flags flags) 214 { 215 return static_cast<std::underlying_type_t<transfer_flags>>(flags) == 0; 216 } 217 218 namespace ftp_transfer_flags 219 { 220 auto constexpr ascii = transfer_flags::protocol_reserved_max; 221 } 222 223 class FZC_PUBLIC_SYMBOL CFileTransferCommand final : public CCommandHelper<CFileTransferCommand, Command::transfer> 224 { 225 public: 226 CFileTransferCommand(reader_factory_holder const& reader, CServerPath const& remotePath, std::wstring const& remoteFile, transfer_flags const& flags); 227 CFileTransferCommand(writer_factory_holder const& writer, CServerPath const& remotePath, std::wstring const& remoteFile, transfer_flags const& flags); 228 229 CServerPath GetRemotePath() const; 230 std::wstring GetRemoteFile() const; Download()231 bool Download() const { return flags_ & transfer_flags::download; } GetFlags()232 transfer_flags const& GetFlags() const { return flags_; } 233 234 bool valid() const; 235 GetReader()236 reader_factory_holder const& GetReader() const { return reader_; } GetWriter()237 writer_factory_holder const& GetWriter() const { return writer_; } 238 protected: 239 reader_factory_holder const reader_; 240 writer_factory_holder const writer_; 241 CServerPath const m_remotePath; 242 std::wstring const m_remoteFile; 243 transfer_flags const flags_; 244 }; 245 246 class FZC_PUBLIC_SYMBOL CHttpRequestCommand final : public CCommandHelper<CHttpRequestCommand, Command::httprequest> 247 { 248 public: 249 CHttpRequestCommand(fz::uri const& uri, writer_factory_holder const& output, std::string const& verb = std::string("GET"), reader_factory_holder const& body = reader_factory_holder(), bool confidential_qs = false) uri_(uri)250 : uri_(uri) 251 , verb_(verb) 252 , body_(body) 253 , output_(output) 254 , confidential_qs_(confidential_qs) 255 {} 256 257 fz::uri const uri_; 258 std::string const verb_; 259 260 reader_factory_holder body_; 261 writer_factory_holder output_; 262 263 bool confidential_qs_{}; 264 }; 265 266 class FZC_PUBLIC_SYMBOL CRawCommand final : public CCommandHelper<CRawCommand, Command::raw> 267 { 268 public: 269 explicit CRawCommand(std::wstring const& command); 270 271 std::wstring GetCommand() const; 272 valid()273 bool valid() const { return !m_command.empty(); } 274 275 protected: 276 std::wstring m_command; 277 }; 278 279 class FZC_PUBLIC_SYMBOL CDeleteCommand final : public CCommandHelper<CDeleteCommand, Command::del> 280 { 281 public: 282 CDeleteCommand(CServerPath const& path, std::vector<std::wstring> && files); 283 GetPath()284 CServerPath GetPath() const { return m_path; } GetFiles()285 const std::vector<std::wstring>& GetFiles() const { return files_; } ExtractFiles()286 std::vector<std::wstring>&& ExtractFiles() { return std::move(files_); } 287 valid()288 bool valid() const { return !GetPath().empty() && !GetFiles().empty(); } 289 protected: 290 CServerPath const m_path; 291 std::vector<std::wstring> files_; 292 }; 293 294 class FZC_PUBLIC_SYMBOL CRemoveDirCommand final : public CCommandHelper<CRemoveDirCommand, Command::removedir> 295 { 296 public: 297 // Directories can either be given as absolute path or as 298 // pair of an absolute path and the very last path segments. 299 CRemoveDirCommand(CServerPath const& path, std::wstring const& subdDir); 300 GetPath()301 CServerPath GetPath() const { return m_path; } GetSubDir()302 std::wstring GetSubDir() const { return m_subDir; } 303 304 bool valid() const; 305 306 protected: 307 CServerPath const m_path; 308 std::wstring const m_subDir; 309 }; 310 311 class FZC_PUBLIC_SYMBOL CMkdirCommand final : public CCommandHelper<CMkdirCommand, Command::mkdir> 312 { 313 public: 314 explicit CMkdirCommand(CServerPath const& path); 315 GetPath()316 CServerPath GetPath() const { return m_path; } 317 318 bool valid() const; 319 320 protected: 321 CServerPath const m_path; 322 }; 323 324 class FZC_PUBLIC_SYMBOL CRenameCommand final : public CCommandHelper<CRenameCommand, Command::rename> 325 { 326 public: 327 CRenameCommand(CServerPath const& fromPath, std::wstring const& fromFile, 328 CServerPath const& toPath, std::wstring const& toFile); 329 GetFromPath()330 CServerPath GetFromPath() const { return m_fromPath; } GetToPath()331 CServerPath GetToPath() const { return m_toPath; } GetFromFile()332 std::wstring GetFromFile() const { return m_fromFile; } GetToFile()333 std::wstring GetToFile() const { return m_toFile; } 334 335 bool valid() const; 336 337 protected: 338 CServerPath const m_fromPath; 339 CServerPath const m_toPath; 340 std::wstring const m_fromFile; 341 std::wstring const m_toFile; 342 }; 343 344 class FZC_PUBLIC_SYMBOL CChmodCommand final : public CCommandHelper<CChmodCommand, Command::chmod> 345 { 346 public: 347 // The permission string should be given in a format understandable by the server. 348 // Most likely it's the default octal representation used by the unix chmod command, 349 // i.e. chmod 755 foo.bar 350 CChmodCommand(CServerPath const& path, std::wstring const& file, std::wstring const& permission); 351 GetPath()352 CServerPath GetPath() const { return m_path; } GetFile()353 std::wstring GetFile() const { return m_file; } GetPermission()354 std::wstring GetPermission() const { return m_permission; } 355 356 bool valid() const; 357 358 protected: 359 CServerPath const m_path; 360 std::wstring const m_file; 361 std::wstring const m_permission; 362 }; 363 364 #endif 365