1/*
2 * Copyright 1998-1999 Be, Inc. All Rights Reserved.
3 * Copyright 2003-2019 Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "SftpClient.h"
9
10#include <unistd.h>
11
12#include <String.h>
13
14
15SftpClient::SftpClient()
16	:
17	SpawningUploadClient()
18{
19}
20
21
22SftpClient::~SftpClient()
23{
24	if (OutputPipe() >= 0)
25		SendCommand("quit\n");
26}
27
28
29bool
30SftpClient::ChangeDir(const string& dir)
31{
32	int len;
33	BString cmd("cd");
34	BString reply;
35
36	cmd << " " << dir.c_str() << "\n";
37	SendCommand(cmd.String());
38
39	len = ReadReply(&reply);
40	if (len < 0) {
41		fprintf(stderr, _GetReadText(), len);
42		return false;
43	}
44
45	fprintf(stderr, _GetReplyText(), reply.String());
46	if (reply.FindFirst("sftp>") < 0)
47		return false;
48
49	return true;
50}
51
52
53bool
54SftpClient::ListDirContents(string& listing)
55{
56	int len;
57	BString reply;
58
59	SendCommand("ls\n");
60	do {
61		len = ReadReply(&reply);
62		if (len < 0) {
63			fprintf(stderr, _GetReadText(), len);
64			return false;
65		}
66		fprintf(stderr, _GetReplyText(), reply.String());
67		printf("%s", reply.String());
68		if (reply.FindFirst("sftp>") == 0)
69			return true;
70	} while (true);
71
72	return false;
73}
74
75
76bool
77SftpClient::PrintWorkingDir(string& dir)
78{
79	SendCommand("pwd\n");
80	return false;
81}
82
83
84bool
85SftpClient::Connect(const string& server, const string& login,
86	const string& passwd)
87{
88	BString cmd("sftp ");
89	BString host(server.c_str());
90	BString port;
91
92	if (host.FindFirst(':'))
93		host.MoveInto(port, host.FindFirst(':'), host.Length());
94	port.RemoveAll(":");
95
96	if (port.Length())
97		cmd << "-oPort=" << port << " ";
98
99	cmd << login.c_str();
100	cmd << "@" << host.String();
101	printf("COMMAND: '%s'\n", cmd.String());
102	SetCommandLine(cmd.String());
103
104	if (!SpawningUploadClient::Connect(server, login, passwd))
105		return false;
106
107	BString reply;
108	ssize_t len;
109
110	len = ReadReply(&reply);
111	if (len < 0) {
112		fprintf(stderr, _GetLongReadText(), len);
113		return false;
114	}
115	fprintf(stderr, _GetReplyText(), reply.String());
116	if (reply.FindFirst("Connecting to ") != 0)
117		return false;
118
119	len = ReadReply(&reply);
120	if (len < 0) {
121		fprintf(stderr, _GetLongReadText(), len);
122		return false;
123	}
124
125	fprintf(stderr, _GetReplyText(), reply.String());
126	if (reply.FindFirst(/*[pP]*/"assword:") < 0)
127		return false;
128
129	write(OutputPipe(), passwd.c_str(), strlen(passwd.c_str()));
130	write(OutputPipe(), "\n", 1);
131
132	len = ReadReply(&reply);
133	if (len < 0) {
134		fprintf(stderr, _GetLongReadText(), len);
135		return false;
136	}
137
138	fprintf(stderr, _GetReplyText(), reply.String());
139	if (reply != "\n")
140		return false;
141
142	len = ReadReply(&reply);
143	if (len < 0) {
144		fprintf(stderr, _GetLongReadText(), len);
145		return false;
146	}
147
148	fprintf(stderr, _GetReplyText(), reply.String());
149	if (reply.FindFirst("sftp>") < 0)
150		return false;
151
152	return true;
153}
154
155
156bool
157SftpClient::PutFile(const string& local, const string& remote, ftp_mode mode)
158{
159	int len;
160	//XXX: handle mode ?
161	BString cmd("put");
162	cmd << " " << local.c_str() << " " << remote.c_str() << "\n";
163	SendCommand(cmd.String());
164
165	BString reply;
166
167	len = ReadReply(&reply);
168	if (len < 0) {
169		fprintf(stderr, _GetReadText(), len);
170		return false;
171	}
172
173	fprintf(stderr, _GetReplyText(), reply.String());
174	if (reply.FindFirst("Uploading") < 0)
175		return false;
176
177	len = ReadReply(&reply);
178	if (len < 0) {
179		fprintf(stderr, _GetReadText(), len);
180		return false;
181	}
182
183	fprintf(stderr, _GetReplyText(), reply.String());
184	if (reply.FindFirst("sftp>") < 0)
185		return false;
186
187	return true;
188}
189
190
191bool
192SftpClient::GetFile(const string& remote, const string& local, ftp_mode mode)
193{
194	//XXX
195	return false;
196}
197
198
199// Note: this only works for local remote moves, cross filesystem moves
200// will not work
201bool
202SftpClient::MoveFile(const string& oldPath, const string& newPath)
203{
204	int len;
205
206	// sftpd can't rename to an existing file...
207	BString cmd("rm");
208	cmd << " " << newPath.c_str() << "\n";
209	fprintf(stderr, "CMD: '%s'\n", cmd.String());
210	SendCommand(cmd.String());
211	BString reply;
212
213	len = ReadReply(&reply);
214	if (len < 0) {
215		fprintf(stderr, _GetReadText(), len);
216		return false;
217	}
218
219	fprintf(stderr, _GetReplyText(), reply.String());
220	// we don't care if it worked or not.
221	//if (reply.FindFirst("Removing") != 0 && reply.FindFirst("Couldn't") )
222	//	return false;
223
224	len = ReadReply(&reply);
225	if (len < 0) {
226		fprintf(stderr, _GetReadText(), len);
227		return false;
228	}
229
230	fprintf(stderr, _GetReplyText(), reply.String());
231	if (reply.FindFirst("sftp>") < 0)
232		return false;
233
234	cmd = "rename";
235	cmd << " " << oldPath.c_str() << " " << newPath.c_str() << "\n";
236	SendCommand(cmd.String());
237
238	len = ReadReply(&reply);
239	if (len < 0) {
240		fprintf(stderr, _GetReadText(), len);
241		return false;
242	}
243
244	fprintf(stderr, _GetReplyText(), reply.String());
245	if (reply.FindFirst("sftp>") < 0)
246		return false;
247
248	return true;
249}
250
251
252bool
253SftpClient::Chmod(const string& path, const string& mod)
254{
255	int len;
256	//XXX: handle mode ?
257	BString cmd("chmod");
258	cmd << " " << mod.c_str() << " " << path.c_str() << "\n";
259	SendCommand(cmd.String());
260
261	BString reply;
262
263	len = ReadReply(&reply);
264	if (len < 0) {
265		fprintf(stderr, _GetReadText(), len);
266		return false;
267	}
268
269	fprintf(stderr, _GetReplyText(), reply.String());
270	if (reply.FindFirst("Changing") < 0)
271		return false;
272
273	len = ReadReply(&reply);
274	if (len < 0) {
275		fprintf(stderr, _GetReadText(), len);
276		return false;
277	}
278
279	fprintf(stderr, _GetReplyText(), reply.String());
280	if (reply.FindFirst("sftp>") < 0)
281		return false;
282
283	return true;
284}
285
286
287void
288SftpClient::SetPassive(bool on)
289{
290}
291
292
293const char*
294SftpClient::_GetLongReadText() const
295{
296	return B_TRANSLATE("read: %ld\n");
297}
298
299
300const char*
301SftpClient::_GetReadText() const
302{
303	return B_TRANSLATE("read: %d\n");
304}
305
306
307const char*
308SftpClient::_GetReplyText() const
309{
310	return B_TRANSLATE("reply: '%s'\n");
311}
312