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