#! /usr/bin/env python
""" Searches given ftp for string. U can use either a regexp
	or string. No proxy implemented, connects as passive. 

usage:
	ftpsearch login:pass@ftp[:port] ("string i want")|("regexp" -r)
examples:
    ftpsearch.py mylogin:mypass@myhost.com:1088 \"^[0-9]+.*$\" -r";
	ftplist.py mylogin:mypass@127.0.0.1 \"string to search\"";
"""

from ftplib import FTP;
import sys, re;

global ftp, string, reg, found;

#print credits
def credits():
	print "";
	print "@=====ftpsearch 0.1b==starenka 2oo6=====@";
	print "@     mailto:toad2(at)seznam(dot)cz     @";
	print "@=======================================@";
	print "";

#shows help message
def usage():
	print "";
	print "usage: ftpsearch.py mylogin:mypass@myhost.com[:port] (\"string to search\")|(\"regexp\" -r)";
	print "       ftpsearch.py mylogin:mypass@myhost.com:1088 \"^[0-9]+.*$\" -r";
	print "       ftplist.py mylogin:mypass@127.0.0.1 \"string to search\"";
	print "";
	print "       for further nfo on Python regexp pls read http://www.python.org/doc/howto/";

#connectsto ftp and starts listing
def go( host, port, login, pwd ):
	global ftp;
	ftp = FTP();
	try:
		print "connection\n==========";
		ftp.connect( host, port )
		print "connected to ftp://"+host+":"+port+"\n[msg]: "+ftp.getwelcome();
		try:
			ftp.login( login, pwd );
			print "logged in...\n\nsearch\n======";
			if( reg == 1 ):
				print "searching for r e g e x p "+sys.argv[2];
			else:
				print "searching for s t r i n g "+sys.argv[2];
			print "";
			listDir( '/' );
		except: 
			print "[err]: 530 failed to log in ("+login+":"+pwd+"). Check the username & pass..";
		ftp.quit();
	except:
		print "[err]: failed to connect to ftp - connection refused: "+host+":"+port; 

#recursive listing
def listDir( path ):
	global ftp, found;
	listing = [];
	try:
		ftp.cwd( path );
		ftp.retrlines( 'LIST', listing.append );
		for line in listing:
			x = line.split( None, 8 );
			if( x[8] != '.' and x[8] != '..' ):
				if( x[0].startswith( "d" ) ):
					#list.setdefault(path, []).append(x[8]+" [dir] ");
					if( matchesString( x[8] ) ):
						print "["+repr( found+1 )+"] [dir] "+x[8]+" (in "+path[1:len( path )]+")";
						found += 1;
					listDir( path+"/"+x[8] );
				else:
					#list.setdefault(path, []).append(x[8]);
					if( matchesString( x[8] ) ):
						print "["+repr( found+1 )+"] "+x[8]+" (in "+path[1:len( path )]+")";
						found += 1;
	except:
		print "[warn]: Failed to CWD ("+path+")";

#tests ftp address
def isFtp( adr ):
	patt = "(^[\.a-zA-Z0-9_-]+:[\.a-zA-Z0-9_-]+@)|(^)[\.a-zA-Z0-9_-]+(:[0-9]{0,4})*$";
	x = re.match( patt, adr );
	if( x != None ):
		return 1;
	else:
		return 0;

#compares found string w/ searched
def matchesString( where ):
	global string, reg;
	
	if( reg == 1 ): #use regexp
		x = re.match( string, where );
		if( x != None ):
			return 1;
		else:
			return 0;
	else:
		f = where.find( string );
		if( f != -1 ):
			return 1;
		else:
			return 0;
		
#prints results
def results():
	global found, string;
	print "";
	print "found: "+repr( found )+" matches";
		
found = 0;
credits();
#testing args
if( len( sys.argv )>=3 ):
	if( isFtp( sys.argv[1] ) ):
		string = sys.argv[2];
		try:
			if( sys.argv[3] == "-r" ):
				reg = 1;
		except:
			reg = 0;
		x = sys.argv[1].split( '@', 1 );
		if( len( x ) == 2 ): #has a login nfo
			y = x[0].split( ':', 1 );
			login = y[0];
			pwd = y[1];
			y = x[1].split( ":", 1 );
			if( len( y ) == 2 ): #has port nfo
				port = y[1];
			else:
				port = '21';
			host = y[0];
		else:
			print "[warn]: no login. asuming anonymous";
			login = "anonymous";
			pwd = "just@fun.org";
			y = x[0].split( ":", 1 );
			if( len( y ) == 2 ): #has port nfo
				port = y[1];
			else:
				port = '21';
			host = y[0];
		list = {};
		go( host, port, login, pwd );
		results();
	else:
		print "[err]: invalid ftp address... ("+sys.argv[1]+")";
		usage();
else:
	print "[err]: missing arguments...";
	usage();
