1 /********************************************************************************
2  *                              Nepenthes
3  *                        - finest collection -
4  *
5  *
6  *
7  * Copyright (C) 2005  Paul Baecher & Markus Koetter
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22  *
23  *
24  *             contact nepenthesdev@users.sourceforge.net
25  *
26  *******************************************************************************/
27 
28 /* $Id: VFSCommandFTP.cpp 1410 2007-10-12 13:07:23Z common $ */
29 
30 #include <cctype>
31 #include <cstring>
32 
33 #include "VFSCommandFTP.hpp"
34 #include "VFSNode.hpp"
35 #include "VFSDir.hpp"
36 #include "VFSFile.hpp"
37 #include "Nepenthes.hpp"
38 #include "LogManager.hpp"
39 #include "VFS.hpp"
40 #include "DownloadManager.hpp"
41 #include "Dialogue.hpp"
42 #include "Socket.hpp"
43 #include "Download.hpp"
44 
45 #ifdef STDTAGS
46 #undef STDTAGS
47 #endif
48 #define STDTAGS l_shell
49 
50 using namespace nepenthes;
51 using namespace std;
52 
VFSCommandFTP(VFSNode * parent,VFS * vfs)53 VFSCommandFTP::VFSCommandFTP(VFSNode *parent,VFS *vfs)
54 {
55 	m_Name =	"ftp.exe";
56 	m_ParentNode = parent;
57 	m_Type = VFS_EXE;
58 	m_VFS = vfs;
59 }
60 
~VFSCommandFTP()61 VFSCommandFTP::~VFSCommandFTP()
62 {
63 
64 }
65 
66 
67 /*
68 C:\>ftp -h
69 
70 Überträgt Dateien zu und von einem Computer, der den TFTP-Dienst ausführt
71 (auch Daemon genannt).
72 
73 FTP kann interaktiv verwendet werden.
74 
75 FTP [-v] [-d] [-i] [-n] [-g] [-s:Dateiname] [-a] [-w:Fenstergröße] [-A]
76     [Host]
77 
78   -v             Unterdrückt das Anzeigen der Rückmeldungen von
79                  Remoteservern.
80   -n             Unterdrückt das automatische Anmelden nach dem ersten
81                  Verbindungsaufbau.
82   -i             Deaktiviert die interaktive Eingabe, während mehrere
83                  Dateien übertragen werden.
84   -d             Aktiviert Debugging.
85   -g             Deaktiviert "Globbing" des Dateinamens (siehe auch GLOB-
86                  Befehl).
87   -s:Dateiname   Gibt eine Textdatei an, die FTP-Befehle enthält. Die
88                  Befehle werden nach dem Starten von FTP automatisch
89                  ausgeführt.
90   -a             Verwendet eine beliebige lokale Schnittstelle, wenn
91                  Datenverbindungen gebunden werden.
92   -A             Meldet den Benutzer als "Anonymus" an.
93   -w:Puffergröße Überschreibt die Standardgröße des Übertragungspuffers
94                  von 4096.
95   Host           Gibt den Hostnamen oder die IP-Adresse des Remotehosts
96                  an, zu dem eine Verbindung hergestellt wird.
97 
98 Hinweis:
99   - Die Befehle "mget" und "mput" akzeptieren y/n/q für yes/no/quit.
100   - Verwenden Sie STRG+C zum Abbrechen von Befehlen.
101 */
102 
103 
run(vector<string> * paramlist)104 int32_t VFSCommandFTP::run(vector<string> *paramlist)
105 {
106 
107 	bool direktconnect = true;
108 	bool anonymouslogin = false;
109 
110 	vector <string> slist = *paramlist;
111 	vector <string>::iterator it;
112 	string host = "nohostyet";
113 	string port = "21";
114 	string user = "nouseryet";
115 	string pass = "nopassyet";
116 	string getfile = "nofileyet";
117 	string path = "";
118 
119 	string filename = "";
120 	uint8_t	downloadflags=0;
121 
122 
123 	for(it=slist.begin();it!=slist.end();it++)
124 	{
125 // FTP [-v] [-d] [-i] [-n] [-g] [-s:Dateiname] [-a] [-w:Fenstergr��e] [-A]     [Host]
126 
127 		logDebug("ftp.exe param %s \n",&*it->c_str());
128 		if (strncmp(&*it->c_str(),"-v",2) == 0)
129 			continue;
130 		else
131 		if (strncmp(&*it->c_str(),"-d",2) == 0) // debugging
132 			continue;
133 		else
134 		if (strncmp(&*it->c_str(),"-i",2) == 0)	// non interactive
135 			continue;
136 		else
137 		if (strncmp(&*it->c_str(),"-n",2) == 0)
138 		{
139 			direktconnect = false;
140 			continue;
141 		}
142 		else
143 		if (strncmp(&*it->c_str(),"-a",2) == 0)	// idiotic description i guess binding the port on any interface using active ftp
144 			continue;
145 		else
146         if (strncmp(&*it->c_str(),"-w:",3) == 0)	// window size foobar
147 			continue;
148 		else
149 		if (strncmp(&*it->c_str(),"-s:",3) == 0)
150 		{
151 			filename = it->substr(3,it->size()-2);
152 		}else
153         if (strncmp(&*it->c_str(),"-A",2) == 0)	// anonymous login
154 		{
155 			anonymouslogin = true;
156 			user = "anonymous";
157 			pass = "guest";
158 		}
159 		else
160 			host = *it;
161 	}
162 
163 	if (filename != "" )
164 	{
165 		logDebug("Filenameis %s\n",filename.c_str());
166 		VFSFile *file = m_VFS->getCurrentDir()->getFile((char *)filename.c_str());
167 		if (file == NULL)
168 		{
169 			logCrit("VFS FTP file %s not found\n",filename.c_str());
170 			return 0;
171 		}
172 		logDebug("file content is is \n%.*s\n",file->getSize(),(char *)file->getData());
173 
174 		uint32_t i=0;
175 		int32_t linestart=0;
176 		int32_t linestopp=0;
177 		vector <string> ftpcommands;
178 		while(i<file->getSize())
179 		{
180 			if (memcmp(file->getData()+i,"\n",1) == 0)
181 			{
182 
183 				i++;
184 				linestopp = i;
185 
186 				logSpam(" line is '%.*s'\n",linestopp-linestart,file->getData()+linestart);
187 				string command( file->getData()+linestart,linestopp-linestart-1);
188 				ftpcommands.push_back(command);
189 				linestart = linestopp;
190 			}
191 			i++;
192 		}
193 
194 
195 		vector <string>::iterator jt;
196 		vector <string> paramlist;
197 
198 		ftp_command_state state = NEXT_IS_SOMETHING;
199 
200 		for ( jt=ftpcommands.begin();jt!=ftpcommands.end();jt++ )
201 		{
202 			string params(&*jt->c_str());
203 			i=0;
204 			bool haschar = false;
205 			uint32_t wordstart=0;
206 			uint32_t wordstopp=0;
207 			paramlist.clear();
208 			while ( i<=params.size() )
209 			{
210 				if ( ( ( params[i] == ' ' || params[i] == '\0') && haschar == true) )
211 				{
212 					wordstopp = i;
213 					string word = params.substr(wordstart,wordstopp-wordstart);
214 					logDebug("Word is %i %i '%s' \n",wordstart,wordstopp,word.c_str());
215 					paramlist.push_back(word);
216 					haschar = false;
217 				} else
218 					if ( isgraph(params[i]) && haschar == false )
219 				{
220 					haschar = true;
221 					wordstart = i;
222 				}
223 				i++;
224 			}
225 
226 
227 
228 			switch (state)
229 			{
230 
231 			case NEXT_IS_SOMETHING:
232 				if ( strncasecmp((char *)&*jt->c_str(),"open",4) == 0 )
233 				{
234 					logSpam("open line %s \n",&*jt->c_str());
235 					switch(paramlist.size())
236 					{
237 					case 1:
238 						state = NEXT_IS_HOST;
239 						break;
240 					default:
241 						host = paramlist[1];
242 						if ( paramlist.size() >=3 )
243 							port = paramlist[2];
244 						else
245 							port = "21";
246 
247 						if(direktconnect == true && anonymouslogin == false)
248 						{
249 							state = NEXT_IS_USER;
250 						}else
251 						{
252 							state = NEXT_IS_SOMETHING;
253 						}
254 
255 						break;
256 
257 					}
258 
259 					logDebug("ftp://%s:%s\n",host.c_str(),port.c_str());
260 				} else
261 				if ( strncasecmp((char *)&*jt->c_str(),"user",4) == 0 )
262 				{
263 					if ( direktconnect == true )
264 					{
265 						logCrit("VFS FTP State ERROR user\n");
266 					} else
267 					{
268 
269 						switch ( paramlist.size() )
270 						{
271 						case 1:
272 							state = NEXT_IS_USER;
273 							break;
274 
275 						case 2:
276 							user = paramlist[1];
277 							state = NEXT_IS_PASS;
278 							break;
279 						case 3:
280 							user = paramlist[1];
281 							pass = paramlist[2];
282 							break;
283 						}
284 						logDebug("ftp://%s:%s@%s:%s\n",user.c_str(),pass.c_str(),host.c_str(),port.c_str());
285 					}
286 				} else
287 				if ( strncasecmp((char *)&*jt->c_str(),"get",3) == 0 )
288 				{
289 					switch(paramlist.size())
290 					{
291 					case 1:
292 						state = NEXT_IS_FILE;
293 						logDebug("get without param, next arg is filename\n");
294 						break;
295 					default:
296 						getfile = paramlist[1];
297 //							logDebug("ftp://%s:%s@%s:%s/%s\n",user.c_str(),pass.c_str(),host.c_str(),port.c_str(),getfile.c_str());
298 						startDownload(host,port,user,pass,path,getfile,downloadflags);
299 					}
300 				}else
301 				if ( strncasecmp((char *)&*jt->c_str(),"binary",6) == 0 ||
302 					 strncasecmp((char *)&*jt->c_str(),"bin",3) == 0)
303 				{
304 					downloadflags |= DF_TYPE_BINARY;
305 				}else
306 				if ( strncasecmp((char *)&*jt->c_str(),"cd",2) == 0 )
307 				{
308 					switch ( paramlist.size() )
309 					{
310 					case 1:
311 						state = NEXT_IS_PATH;
312 						break;
313 
314 					case 2:
315 						path = paramlist[1];
316 						break;
317 					}
318 
319 				}
320 
321 				break;
322 
323 
324 
325 			case NEXT_IS_HOST:
326 				switch ( paramlist.size() )
327 				{
328 
329 				case 1:
330 					host = paramlist[0];
331 					port = "21";
332 					break;
333 
334 				case 2:
335 					host = paramlist[0];
336 					port = paramlist[1];
337 					break;
338 				}
339 
340 				if(direktconnect == true && anonymouslogin == false )
341 				{
342 					state = NEXT_IS_USER;
343 				}else
344 				{
345 					state = NEXT_IS_SOMETHING;
346 				}
347 				break;
348 
349 
350 			case NEXT_IS_PORT:
351 				break;
352 
353 			case NEXT_IS_USER:
354 				switch ( paramlist.size() )
355 				{
356 				case 1:
357 					user = paramlist[0];
358 					state = NEXT_IS_PASS;
359 					break;
360 
361 				default:
362 					logCrit("Broken State NEXT_IS_USER\n");
363 					state = NEXT_IS_SOMETHING;
364 					break;
365 				}
366 				break;
367 
368 			case NEXT_IS_PASS:
369 				pass = paramlist[0];
370 				state = NEXT_IS_SOMETHING;
371 				break;
372 
373 
374 			case NEXT_IS_FILE:
375 				getfile = paramlist[0];
376 				startDownload(host,port,user,pass,path,getfile,downloadflags);
377 				state = NEXT_IS_SOMETHING;
378 				break;
379 
380 			case NEXT_IS_PATH:
381 				path = paramlist[0];
382 				state = NEXT_IS_SOMETHING;
383 				break;
384 
385 			}
386 
387 		}
388 
389 	}
390     return 0;
391 }
392 
startDownload(string host,string port,string user,string pass,string path,string getfile,uint8_t downloadflags)393 bool VFSCommandFTP::startDownload(string host, string port, string user, string pass, string path, string getfile, uint8_t downloadflags)
394 {
395 	logPF();
396 	string url;
397 	string file;
398 
399 	if (path == "")
400 	{
401 		url = "ftp://" + user + ":" + pass + "@" + host+ ":" + port + "/" + getfile;
402 	}else
403 	{
404 		url = "ftp://" + user + ":" + pass + "@" + host+ ":" + port;
405 
406 		int pathlen = path.size()-1;
407 		if (path[0] != '/' )
408 		{
409 			url += "/" + path;
410 			file += "/" + path;
411 		}
412 		if (path[pathlen] != '/')
413 		{
414 			url += "/";
415 			file += "/";
416 		}
417 		url += getfile;
418 		file += getfile;
419 	}
420 
421 	uint32_t remotehost = 0;
422 	uint32_t localhost = 0;
423 
424 	if (m_VFS->getDialogue()->getSocket() != NULL)
425 	{
426 		logSpam("VFSCommandFTP Setting Hosts %i %i\n",remotehost,localhost);
427 		remotehost = m_VFS->getDialogue()->getSocket()->getRemoteHost();
428 		localhost  = m_VFS->getDialogue()->getSocket()->getLocalHost();
429 	}
430 
431 	logSpam("VFSCommandFTP LocalHost %s\n",inet_ntoa(*(in_addr *)&localhost));
432 	logSpam("VFSCommandFTP RemoteHost %s\n",inet_ntoa(*(in_addr *)&remotehost));
433 
434 	if (strstr(user.c_str(),"@") == NULL && strstr(pass.c_str(),"@") == NULL)
435 	{
436 		g_Nepenthes->getDownloadMgr()->downloadUrl(	localhost,
437 													(char *)url.c_str(),
438 													remotehost,
439 													(char *)url.c_str(),
440 													downloadflags);
441 	}else
442 	{
443 		g_Nepenthes->getDownloadMgr()->downloadUrl(	localhost,
444 													(char *)"ftp",
445 												   (char *)user.c_str(),
446 												   (char *)pass.c_str(),
447 												   (char *)host.c_str(),
448 												   (char *)port.c_str(),
449 												   (char *)file.c_str(),
450 												   remotehost,
451 												   downloadflags);
452 	}
453 	return true;
454 }
455