FTP Convert to LibMist
This commit is contained in:
		
							parent
							
								
									8a9d4d6ee1
								
							
						
					
					
						commit
						0ac64dd6cb
					
				
					 5 changed files with 820 additions and 2 deletions
				
			
		|  | @ -1,9 +1,9 @@ | |||
| lib_LTLIBRARIES=libmist-1.0.la | ||||
| libmist_1_0_la_SOURCES=amf.h amf.cpp auth.h auth.cpp base64.h base64.cpp config.h config.cpp crypto.h crypto.cpp dtsc.h dtsc.cpp flv_tag.h flv_tag.cpp http_parser.h http_parser.cpp json.h json.cpp procs.h procs.cpp rtmpchunks.h rtmpchunks.cpp socket.h socket.cpp mp4.h mp4.cpp | ||||
| libmist_1_0_la_SOURCES=amf.h amf.cpp auth.h auth.cpp base64.h base64.cpp config.h config.cpp crypto.h crypto.cpp dtsc.h dtsc.cpp flv_tag.h flv_tag.cpp http_parser.h http_parser.cpp json.h json.cpp procs.h procs.cpp rtmpchunks.h rtmpchunks.cpp socket.h socket.cpp mp4.h mp4.cpp ftp.h ftp.cpp filesystem.h filesystem.cpp | ||||
| libmist_1_0_la_LIBADD=-lssl -lcrypto | ||||
| 
 | ||||
| pkgconfigdir = $(libdir)/pkgconfig | ||||
| pkgconfig_DATA = mist-1.0.pc | ||||
| 
 | ||||
| library_includedir=$(includedir)/mist-1.0/mist | ||||
| library_include_HEADERS = amf.h auth.h base64.h config.h crypto.h dtsc.h flv_tag.h http_parser.h json.h procs.h rtmpchunks.h socket.h mp4.h | ||||
| library_include_HEADERS = amf.h auth.h base64.h config.h crypto.h dtsc.h flv_tag.h http_parser.h json.h procs.h rtmpchunks.h socket.h mp4.h ftp.h filesystem.h | ||||
|  |  | |||
							
								
								
									
										273
									
								
								lib/filesystem.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								lib/filesystem.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,273 @@ | |||
| #include "filesystem.h" | ||||
| 
 | ||||
| 
 | ||||
| Filesystem::Directory::Directory( std::string PathName, std::string BasePath ) { | ||||
|   MyBase = BasePath; | ||||
|   if( PathName[0] == '/' ) { PathName.erase(0,1); } | ||||
|   if( BasePath[BasePath.size()-1] != '/' ) { BasePath += "/"; } | ||||
|   MyPath = PathName; | ||||
|   FillEntries( ); | ||||
| } | ||||
| 
 | ||||
| Filesystem::Directory::~Directory( ) { } | ||||
| 
 | ||||
| void Filesystem::Directory::FillEntries( ) { | ||||
|   fprintf( stderr, "Filling Entries of %s:\n", (MyBase + MyPath).c_str() ); | ||||
|   ValidDir = true; | ||||
|   struct stat StatBuf; | ||||
|   Entries.clear(); | ||||
|   DIR * Dirp = opendir( (MyBase + MyPath).c_str() ); | ||||
|   if( !Dirp ) { | ||||
|     ValidDir = false; | ||||
|   } else { | ||||
|     dirent * entry; | ||||
|     while( entry = readdir( Dirp ) ) { | ||||
|       if( stat((MyBase + MyPath + "/" + entry->d_name).c_str(), &StatBuf) == -1 ) { | ||||
|         fprintf( stderr, "\tSkipping %s\n\t\tReason: %s\n", entry->d_name, strerror(errno) ); | ||||
|         continue; | ||||
|       } | ||||
|       ///Convert stat to string
 | ||||
|       Entries[ std::string( entry->d_name ) ] = StatBuf; | ||||
|     } | ||||
|   } | ||||
|   fprintf( stderr, "Valid dir: %d\n", ValidDir ); | ||||
|   fprintf( stderr, "#Entries: %d\n", Entries.size() ); | ||||
| } | ||||
| 
 | ||||
| void Filesystem::Directory::Print( ) { | ||||
|   if( !ValidDir ) { | ||||
|     printf( "%s is not a valid directory\n", (MyBase + MyPath).c_str() ); | ||||
|     return; | ||||
|   } | ||||
|   printf( "%s:\n", (MyBase + MyPath).c_str() ); | ||||
|   for( std::map<std::string, struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++ ) { | ||||
|     printf( "\t%s\n", (*it).first.c_str() ); | ||||
|   } | ||||
|   printf( "\n" ); | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::IsDir( ) { | ||||
|   return ValidDir; | ||||
| } | ||||
| 
 | ||||
| std::string Filesystem::Directory::PWD( ) { | ||||
|   return "/" + MyPath; | ||||
| } | ||||
| 
 | ||||
| std::string Filesystem::Directory::LIST( std::vector<std::string> ActiveStreams ) { | ||||
|   FillEntries( ); | ||||
|   int MyPermissions; | ||||
|   std::stringstream Converter; | ||||
|   passwd* pwd;//For Username
 | ||||
|   group* grp;//For Groupname
 | ||||
|   tm* tm;//For time localisation
 | ||||
|   char datestring[256];//For time localisation
 | ||||
|    | ||||
|   std::string MyLoc = MyBase + MyPath; | ||||
|   if( MyLoc[MyLoc.size()-1] != '/' ) { MyLoc += "/"; } | ||||
|    | ||||
|   for( std::map<std::string,struct stat>::iterator it = Entries.begin(); it != Entries.end(); it++ ) { | ||||
|      | ||||
|     bool Active = ( std::find( ActiveStreams.begin(), ActiveStreams.end(), (*it).first ) != ActiveStreams.end() ); | ||||
|     fprintf( stderr, "%s active?: %d\n", (*it).first.c_str(), Active ); | ||||
|     fprintf( stderr, "\tMyPath: %s\n\tVisible: %d\n", MyPath.c_str(), MyVisible[MyPath] ); | ||||
|     fprintf( stderr, "\t\tBitmask S_ACTIVE: %d\n\t\tBitmask S_INACTIVE: %d\n", MyVisible[MyPath] & S_ACTIVE, MyVisible[MyPath] & S_INACTIVE ); | ||||
|     if( ( Active && ( MyVisible[MyPath] & S_ACTIVE ) ) || ( (!Active) && ( MyVisible[MyPath] & S_INACTIVE ) ) || ( ((*it).second.st_mode / 010000 ) == 4 ) ) { | ||||
|       if( ((*it).second.st_mode / 010000) == 4 ) { Converter << 'd'; } else { Converter << '-'; } | ||||
|       MyPermissions = ( ( (*it).second.st_mode % 010000 ) / 0100 ); | ||||
|       if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; } | ||||
|       if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; } | ||||
|       if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; } | ||||
|       MyPermissions = ( ( (*it).second.st_mode % 0100 ) / 010 ); | ||||
|       if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; } | ||||
|       if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; } | ||||
|       if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; } | ||||
|       MyPermissions = ( (*it).second.st_mode % 010 ); | ||||
|       if( MyPermissions & 4 ) { Converter << 'r'; } else { Converter << '-'; } | ||||
|       if( MyPermissions & 2 ) { Converter << 'w'; } else { Converter << '-'; } | ||||
|       if( MyPermissions & 1 ) { Converter << 'x'; } else { Converter << '-'; } | ||||
|       Converter << ' '; | ||||
|       Converter << (*it).second.st_nlink; | ||||
|       Converter << ' '; | ||||
|       if( (pwd = getpwuid((*it).second.st_uid)) ) { | ||||
|         Converter << pwd->pw_name; | ||||
|       } else { | ||||
|         Converter << (*it).second.st_uid; | ||||
|       } | ||||
|       Converter << ' '; | ||||
|       if( (grp = getgrgid((*it).second.st_gid) ) ) { | ||||
|         Converter << grp->gr_name; | ||||
|       } else { | ||||
|         Converter << (*it).second.st_gid; | ||||
|       } | ||||
|       Converter << ' '; | ||||
|       Converter << (*it).second.st_size; | ||||
|       Converter << ' '; | ||||
|       tm = localtime(&((*it).second.st_mtime)); | ||||
|       strftime(datestring, sizeof(datestring), "%b %d %H:%M", tm); | ||||
|       Converter << datestring; | ||||
|       Converter << ' '; | ||||
|       Converter << (*it).first; | ||||
|       Converter << '\n'; | ||||
|     } | ||||
|   } | ||||
|   return Converter.str(); | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::CWD( std::string Path ) { | ||||
|   if( Path[0] == '/' ) { | ||||
|     Path.erase(0,1); | ||||
|     MyPath = Path; | ||||
|   } else  { | ||||
|     if( MyPath != "" ) { | ||||
|       MyPath += "/"; | ||||
|     } | ||||
|     MyPath += Path; | ||||
|   } | ||||
|   FillEntries(); | ||||
|   printf( "New Path: %s\n", MyPath.c_str() ); | ||||
|   if( MyPermissions.find( MyPath ) != MyPermissions.end() ) { | ||||
|     printf( "\tPermissions: %d\n", MyPermissions[MyPath] ); | ||||
|   } | ||||
|   return SimplifyPath( ); | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::CDUP( ) { | ||||
|   return CWD( ".." ); | ||||
| } | ||||
| 
 | ||||
| std::string Filesystem::Directory::RETR( std::string Path ) { | ||||
|   std::string Result; | ||||
|   std::string FileName; | ||||
|   if( Path[0] == '/' ) { | ||||
|     Path.erase(0,1); | ||||
|     FileName = MyBase + Path; | ||||
|   } else { | ||||
|     FileName = MyBase + MyPath + "/" + Path; | ||||
|   } | ||||
|   std::ifstream File; | ||||
|   File.open( FileName.c_str() ); | ||||
|   while( File.good() ) { Result += File.get(); } | ||||
|   File.close(); | ||||
|   return Result; | ||||
| } | ||||
| 
 | ||||
| void Filesystem::Directory::STOR( std::string Path, std::string Data ) { | ||||
|   if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & P_STOR ) ) { | ||||
|     std::string FileName; | ||||
|     if( Path[0] == '/' ) { | ||||
|       Path.erase(0,1); | ||||
|       FileName = MyBase + Path; | ||||
|     } else { | ||||
|       FileName = MyBase + MyPath + "/" + Path; | ||||
|     } | ||||
|     std::ofstream File; | ||||
|     File.open( FileName.c_str() ); | ||||
|     File << Data; | ||||
|     File.close(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::SimplifyPath( ) { | ||||
|   MyPath += "/"; | ||||
|   fprintf( stderr, "MyPath: %s\n", MyPath.c_str() ); | ||||
|   std::vector<std::string> TempPath; | ||||
|   std::string TempString; | ||||
|   for( std::string::iterator it = MyPath.begin(); it != MyPath.end(); it ++ ) { | ||||
|     if( (*it) == '/' ) { | ||||
|       if( TempString == ".." ) { | ||||
|         if( !TempPath.size() ) { | ||||
|           return false; | ||||
|         } | ||||
|         TempPath.erase( (TempPath.end()-1) ); | ||||
|       } else if ( TempString  != "." && TempString != "" ) { | ||||
|         TempPath.push_back( TempString ); | ||||
|       } | ||||
|       TempString = ""; | ||||
|     } else { | ||||
|       TempString += (*it); | ||||
|     } | ||||
|   } | ||||
|   MyPath = ""; | ||||
|   for( std::vector<std::string>::iterator it = TempPath.begin(); it != TempPath.end(); it++ ) { | ||||
|     MyPath += (*it); | ||||
|     if( it != ( TempPath.end() - 1 ) ) { MyPath += "/"; } | ||||
|   } | ||||
|   if( MyVisible.find( MyPath ) == MyVisible.end() ) { | ||||
|     MyVisible[MyPath] = S_ALL; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::DELE( std::string Path ) { | ||||
|   if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & P_DELE ) ) { | ||||
|     std::string FileName; | ||||
|     if( Path[0] == '/' ) { | ||||
|       Path.erase(0,1); | ||||
|       FileName = MyBase + Path; | ||||
|     } else { | ||||
|       FileName = MyBase + MyPath + "/" + Path; | ||||
|     } | ||||
|     if( std::remove( FileName.c_str() ) ) { | ||||
|       fprintf( stderr, "Removing file %s unsuccesfull\n", FileName.c_str() ); | ||||
|       return false; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::MKD( std::string Path ) { | ||||
|   std::string FileName; | ||||
|   if( Path[0] == '/' ) { | ||||
|     Path.erase(0,1); | ||||
|     FileName = MyBase + Path; | ||||
|   } else { | ||||
|     FileName = MyBase + MyPath + "/" + Path; | ||||
|   } | ||||
|   if( mkdir( FileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) ) { | ||||
|     fprintf( stderr, "Creating directory %s unsuccesfull\n", FileName.c_str() ); | ||||
|     return false; | ||||
|   } | ||||
|   MyVisible[FileName] = S_ALL; | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::Rename( std::string From, std::string To ) { | ||||
|   if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & P_RNFT ) ) { | ||||
|     std::string FileFrom; | ||||
|     if( From[0] == '/' ) { | ||||
|       From.erase(0,1); | ||||
|       FileFrom = MyBase + From; | ||||
|     } else { | ||||
|       FileFrom = MyBase + MyPath + "/" + From; | ||||
|     } | ||||
|     std::string FileTo; | ||||
|     if( To[0] == '/' ) {  | ||||
|       FileTo = MyBase + To; | ||||
|     } else { | ||||
|       FileTo = MyBase + MyPath + "/" + To; | ||||
|     } | ||||
|     if( std::rename( FileFrom.c_str(), FileTo.c_str() ) ) { | ||||
|       fprintf( stderr, "Renaming file %s to %s unsuccesfull\n", FileFrom.c_str(), FileTo.c_str() ); | ||||
|       return false; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| void Filesystem::Directory::SetPermissions( std::string Path, char Permissions ) { | ||||
|   MyPermissions[Path] = Permissions; | ||||
| } | ||||
| 
 | ||||
| bool Filesystem::Directory::HasPermission( char Permission ) { | ||||
|   if( MyPermissions.find( MyPath ) == MyPermissions.end() || ( MyPermissions[MyPath] & Permission ) ) { | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| void Filesystem::Directory::SetVisibility( std::string Pathname, char Visible ) { | ||||
|   MyVisible[Pathname] = Visible; | ||||
| } | ||||
							
								
								
									
										69
									
								
								lib/filesystem.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								lib/filesystem.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,69 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <cstdio> | ||||
| #include <string> | ||||
| #include <cstring> | ||||
| #include <vector> | ||||
| #include <algorithm> | ||||
| #include <map> | ||||
| #include <sstream> | ||||
| #include <fstream> | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <dirent.h> | ||||
| #include <pwd.h> | ||||
| #include <grp.h> | ||||
| #include <time.h> | ||||
| #include <locale.h> | ||||
| #include <langinfo.h> | ||||
| #include <stdint.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| namespace Filesystem { | ||||
|   enum DIR_Permissions { | ||||
|     P_LIST = 0x01,//List
 | ||||
|     P_RETR = 0x02,//Retrieve
 | ||||
|     P_STOR = 0x04,//Store
 | ||||
|     P_RNFT = 0x08,//Rename From/To
 | ||||
|     P_DELE = 0x10,//Delete
 | ||||
|     P_MKD = 0x20,//Make directory
 | ||||
|     P_RMD = 0x40,//Remove directory
 | ||||
|   }; | ||||
|    | ||||
|   enum DIR_Show { | ||||
|     S_NONE = 0x00, | ||||
|     S_ACTIVE = 0x01, | ||||
|     S_INACTIVE = 0x02, | ||||
|     S_ALL = 0x03, | ||||
|   }; | ||||
|    | ||||
|   class Directory { | ||||
|     public: | ||||
|       Directory( std::string PathName = "", std::string BasePath = "."); | ||||
|       ~Directory( ); | ||||
|       void Print( ); | ||||
|       bool IsDir( ); | ||||
|       std::string PWD( ); | ||||
|       std::string LIST( std::vector<std::string> ActiveStreams = std::vector<std::string>() ); | ||||
|       bool CWD( std::string Path ); | ||||
|       bool CDUP( ); | ||||
|       bool DELE( std::string Path ); | ||||
|       bool MKD( std::string Path ); | ||||
|       std::string RETR( std::string Path ); | ||||
|       void STOR( std::string Path, std::string Data ); | ||||
|       bool Rename( std::string From, std::string To ); | ||||
|       void SetPermissions( std::string PathName, char Permissions ); | ||||
|       bool HasPermission( char Permission ); | ||||
|       void SetVisibility( std::string Pathname, char Visible ); | ||||
|     private: | ||||
|       bool ValidDir; | ||||
|       bool SimplifyPath( ); | ||||
|       void FillEntries( ); | ||||
|       std::string MyBase; | ||||
|       std::string MyPath; | ||||
|       std::map< std::string, struct stat > Entries; | ||||
|       std::map< std::string, char > MyPermissions; | ||||
|       std::map< std::string, char > MyVisible; | ||||
|   };//Directory Class
 | ||||
| };//Filesystem namespace
 | ||||
							
								
								
									
										399
									
								
								lib/ftp.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								lib/ftp.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,399 @@ | |||
| #include "ftp.h" | ||||
| 
 | ||||
| FTP::User::User( Socket::Connection NewConnection ) { | ||||
|   Conn = NewConnection; | ||||
|   USER = ""; | ||||
|   PASS = ""; | ||||
|   MODE = MODE_STREAM; | ||||
|   STRU = STRU_FILE; | ||||
|   TYPE = TYPE_ASCII_NONPRINT; | ||||
|   PORT = 20; | ||||
|   RNFR = ""; | ||||
|    | ||||
|   MyDir = Filesystem::Directory( "", FTPBasePath ); | ||||
|   MyDir.SetPermissions( "", Filesystem::P_LIST ); | ||||
|   MyDir.SetPermissions( "Unconverted", Filesystem::P_LIST | Filesystem::P_DELE | Filesystem::P_RNFT | Filesystem::P_STOR | Filesystem::P_RETR ); | ||||
|   MyDir.SetPermissions( "Converted", Filesystem::P_LIST | Filesystem::P_DELE | Filesystem::P_RNFT | Filesystem::P_RETR ); | ||||
|   MyDir.SetPermissions( "OnDemand", Filesystem::P_LIST | Filesystem::P_RETR ); | ||||
|   MyDir.SetPermissions( "Live", Filesystem::P_LIST ); | ||||
|    | ||||
|   MyDir.SetVisibility( "Converted", Filesystem::S_INACTIVE ); | ||||
|   MyDir.SetVisibility( "OnDemand", Filesystem::S_ACTIVE ); | ||||
|    | ||||
|   JSON::Value MyConfig = JSON::fromFile( "/tmp/mist/streamlist" ); | ||||
|   fprintf( stderr, "Streamamount: %d\n", MyConfig["streams"].size() ); | ||||
|   for( JSON::ObjIter it = MyConfig["streams"].ObjBegin(); it != MyConfig["streams"].ObjEnd(); it++ ) { | ||||
|     std::string ThisStream = (*it).second["channel"]["URL"].toString(); | ||||
|     ThisStream.erase( ThisStream.begin() ); | ||||
|     ThisStream.erase( ThisStream.end() - 1 ); | ||||
|     while( ThisStream.find( '/' ) != std::string::npos ) { | ||||
|       ThisStream.erase(0,ThisStream.find('/')+1); | ||||
|     } | ||||
|     ActiveStreams.push_back( ThisStream ); | ||||
|     fprintf( stderr, "\t%s\n", ThisStream.c_str() ); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| FTP::User::~User( ) { } | ||||
| 
 | ||||
| int FTP::User::ParseCommand( std::string Command ) { | ||||
|   Commands ThisCmd = CMD_NOCMD; | ||||
|   if( Command.substr(0,4) == "NOOP" ) { ThisCmd = CMD_NOOP; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "USER" ) { ThisCmd = CMD_USER; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "PASS" ) { ThisCmd = CMD_PASS; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "QUIT" ) { ThisCmd = CMD_QUIT; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "PORT" ) { ThisCmd = CMD_PORT; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "RETR" ) { ThisCmd = CMD_RETR; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "STOR" ) { ThisCmd = CMD_STOR; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "TYPE" ) { ThisCmd = CMD_TYPE; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "MODE" ) { ThisCmd = CMD_MODE; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "STRU" ) { ThisCmd = CMD_STRU; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "EPSV" ) { ThisCmd = CMD_EPSV; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "PASV" ) { ThisCmd = CMD_PASV; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "LIST" ) { ThisCmd = CMD_LIST; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "CDUP" ) { ThisCmd = CMD_CDUP; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "DELE" ) { ThisCmd = CMD_DELE; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "RNFR" ) { ThisCmd = CMD_RNFR; Command.erase(0,5); } | ||||
|   if( Command.substr(0,4) == "RNTO" ) { ThisCmd = CMD_RNTO; Command.erase(0,5); } | ||||
|   if( Command.substr(0,3) == "PWD" ) { ThisCmd = CMD_PWD; Command.erase(0,4); } | ||||
|   if( Command.substr(0,3) == "CWD" ) { ThisCmd = CMD_CWD; Command.erase(0,4); } | ||||
|   if( Command.substr(0,3) == "RMD" ) { ThisCmd = CMD_RMD; Command.erase(0,4); } | ||||
|   if( Command.substr(0,3) == "MKD" ) { ThisCmd = CMD_MKD; Command.erase(0,4); } | ||||
|   if( ThisCmd != CMD_RNTO ) { RNFR = ""; } | ||||
|   switch( ThisCmd ) { | ||||
|     case CMD_NOOP: { | ||||
|       return 200;//Command okay.
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_USER: { | ||||
|       USER = ""; | ||||
|       PASS = ""; | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       USER = ThisCmd; | ||||
|       return 331;//User name okay, need password.
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_PASS: { | ||||
|       if( USER == "" ) { return 503; }//Bad sequence of commands
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       PASS = ThisCmd; | ||||
|       if( !LoggedIn( ) ) { | ||||
|         USER = ""; | ||||
|         PASS =""; | ||||
|         return 530;//Not logged in.
 | ||||
|       } | ||||
|       return 230; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_LIST: { | ||||
|       std::cout << "Listening on :" << MyPassivePort << "\n"; | ||||
|       Socket::Connection Connected = Passive.accept(); | ||||
|       if( Connected.connected() ) { | ||||
|         Conn.write( "125 Data connection already open; transfer starting.\n" ); | ||||
|       } else { | ||||
|         Conn.write( "150 File status okay; about to open data connection.\n" ); | ||||
|       } | ||||
|       while( !Connected.connected() ) { | ||||
|         Connected = Passive.accept(); | ||||
|       } | ||||
|       fprintf( stderr, "Sending LIST information\n" ); | ||||
|       Connected.write( MyDir.LIST( ActiveStreams ) ); | ||||
|       Connected.close( ); | ||||
|       return 226; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_QUIT: { | ||||
|       return 221;//Service closing control connection. Logged out if appropriate.
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_PORT: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       PORT = atoi( Command.c_str() ); | ||||
|       return 200;//Command okay.
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_EPSV: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       MyPassivePort = (rand() % 9999); | ||||
|       std::cout << ":" << MyPassivePort << "\n"; | ||||
|       Passive = Socket::Server(MyPassivePort,"0.0.0.0",true); | ||||
|       return 229; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_PASV: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       MyPassivePort = (rand() % 9999) + 49152; | ||||
|       std::cout << ":" << MyPassivePort << "\n"; | ||||
|       Passive = Socket::Server(MyPassivePort,"0.0.0.0",true); | ||||
|       return 227; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_RETR: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( !MyDir.HasPermission( Filesystem::P_RETR ) ) { return 550; }//Access denied.
 | ||||
|       std::cout << "Listening on :" << MyPassivePort << "\n"; | ||||
|       Socket::Connection Connected = Passive.accept(); | ||||
|       if( Connected.connected() ) { | ||||
|         Conn.write( "125 Data connection already open; transfer starting.\n" ); | ||||
|       } else { | ||||
|         Conn.write( "150 File status okay; about to open data connection.\n" ); | ||||
|       } | ||||
|       while( !Connected.connected() ) { | ||||
|         Connected = Passive.accept(); | ||||
|       } | ||||
|       fprintf( stderr, "Sending RETR information\n" ); | ||||
|       Connected.write( MyDir.RETR( Command ) ); | ||||
|       Connected.close(); | ||||
|       return 226; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_STOR: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( !MyDir.HasPermission( Filesystem::P_STOR ) ) { return 550; }//Access denied.
 | ||||
|       std::cout << "Listening on :" << MyPassivePort << "\n"; | ||||
|       Socket::Connection Connected = Passive.accept(); | ||||
|       if( Connected.connected() ) { | ||||
|         Conn.write( "125 Data connection already open; transfer starting.\n" ); | ||||
|       } else { | ||||
|         Conn.write( "150 File status okay; about to open data connection.\n" ); | ||||
|       } | ||||
|       while( !Connected.connected() ) { | ||||
|         Connected = Passive.accept(); | ||||
|       } | ||||
|       fprintf( stderr, "Reading STOR information\n" ); | ||||
|       std::string Buffer; | ||||
|       while( Connected.spool() ) { } | ||||
|       Buffer = Connected.Received(); | ||||
|       MyDir.STOR( Command, Buffer ); | ||||
|       return 250; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_TYPE: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( Command.size() != 1 && Command.size() != 3 ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       switch( Command[0] ) { | ||||
|         case 'A': { | ||||
|           if( Command.size() > 1 ) { | ||||
|             if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|             if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter.
 | ||||
|           } | ||||
|           TYPE = TYPE_ASCII_NONPRINT; | ||||
|           break; | ||||
|         } | ||||
|         case 'I': { | ||||
|           if( Command.size() > 1 ) { | ||||
|             if( Command[1] != ' ' ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|             if( Command[2] != 'N' ) { return 504; }//Command not implemented for that parameter.
 | ||||
|           } | ||||
|           TYPE = TYPE_IMAGE_NONPRINT; | ||||
|           break; | ||||
|         } | ||||
|         default: { | ||||
|           return 504;//Command not implemented for that parameter.
 | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       return 200;//Command okay.
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_MODE: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( Command[0] != 'S' ) { return 504; }//Command not implemented for that parameter.
 | ||||
|       MODE = MODE_STREAM; | ||||
|       return 200;//Command okay.
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_STRU: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( Command.size() != 1 ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       switch( Command[0] ) { | ||||
|         case 'F': { | ||||
|           STRU = STRU_FILE; | ||||
|           break; | ||||
|         } | ||||
|         case 'R': { | ||||
|           STRU = STRU_RECORD; | ||||
|           break; | ||||
|         } | ||||
|         default: { | ||||
|           return 504;//Command not implemented for that parameter.
 | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       return 200;//Command okay.
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_PWD: { | ||||
|       if( !LoggedIn( ) ) { return 550; }//Not logged in.
 | ||||
|       if( Command != "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       return 2570;//257 -- 0 to indicate PWD over MKD
 | ||||
|       break; | ||||
|     } | ||||
|     case CMD_CWD: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       Filesystem::Directory TmpDir = MyDir; | ||||
|       if( TmpDir.CWD( Command ) ) { | ||||
|         if( TmpDir.IsDir( ) ) { | ||||
|           MyDir = TmpDir; | ||||
|           return 250; | ||||
|         } | ||||
|       } | ||||
|       return 550; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_CDUP: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command != "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       Filesystem::Directory TmpDir = MyDir; | ||||
|       if( TmpDir.CDUP( ) ) { | ||||
|         if( TmpDir.IsDir( ) ) { | ||||
|           MyDir = TmpDir; | ||||
|           return 250; | ||||
|         } | ||||
|       } | ||||
|       return 550; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_DELE: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( !MyDir.DELE( Command ) ) { return 550; } | ||||
|       return 250; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_RMD: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( !MyDir.HasPermission( Filesystem::P_RMD ) ) { return 550; } | ||||
|       if( !MyDir.DELE( Command ) ) { return 550; } | ||||
|       return 250; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_MKD: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( !MyDir.HasPermission( Filesystem::P_MKD ) ) { return 550; } | ||||
|       if( !MyDir.MKD( Command ) ) { return 550; } | ||||
|       return 2571; | ||||
|       break; | ||||
|     } | ||||
|     case CMD_RNFR: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       RNFR = Command; | ||||
|       return 350;//Awaiting further information
 | ||||
|     } | ||||
|     case CMD_RNTO: { | ||||
|       if( !LoggedIn( ) ) { return 530; }//Not logged in.
 | ||||
|       if( Command == "" ) { return 501; }//Syntax error in parameters or arguments.
 | ||||
|       if( RNFR == "" ) { return 503; } //Bad sequence of commands
 | ||||
|       if( !MyDir.Rename( RNFR, Command ) ) { return 550; } | ||||
|       return 250; | ||||
|     } | ||||
|     default: { | ||||
|       return 502;//Command not implemented.
 | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool FTP::User::LoggedIn( ) { | ||||
|   if( USER == "" || PASS == "" ) { return false; } | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| std::string FTP::User::NumToMsg( int MsgNum ) { | ||||
|   std::string Result; | ||||
|   switch( MsgNum ) { | ||||
|     case 200: { | ||||
|       Result = "200 Message okay.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 221: { | ||||
|       Result = "221 Service closing control connection. Logged out if appropriate.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 226: { | ||||
|       Result = "226 Closing data connection.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 227: { | ||||
| 	  std::stringstream sstr; | ||||
|       sstr << "227 Entering passive mode (0,0,0,0,"; | ||||
|       sstr << (MyPassivePort >> 8) % 256; | ||||
|       sstr << ","; | ||||
|       sstr << MyPassivePort % 256; | ||||
|       sstr << ").\n"; | ||||
|       Result = sstr.str(); | ||||
| 	  break; | ||||
| 	} | ||||
|     case 229: { | ||||
|       std::stringstream sstr; | ||||
|       sstr << "229 Entering extended passive mode (|||"; | ||||
|       sstr << MyPassivePort; | ||||
|       sstr << "|).\n"; | ||||
|       Result = sstr.str(); | ||||
|       break; | ||||
|     } | ||||
|     case 230: { | ||||
|       Result = "230 User logged in, proceed.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 250: { | ||||
|       Result = "250 Requested file action okay, completed.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 2570: {//PWD
 | ||||
|       Result = "257 \"" + MyDir.PWD( ) + "\" selected as PWD\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 2571: {//MKD
 | ||||
|       Result = "257 \"" + MyDir.PWD( ) + "\" created\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 331: { | ||||
|       Result = "331 User name okay, need password.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 350: { | ||||
|       Result = "350 Requested file action pending further information\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 501: { | ||||
|       Result = "501 Syntax error in parameters or arguments.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 502: { | ||||
|       Result = "502 Command not implemented.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 503: { | ||||
|       Result = "503 Bad sequence of commands.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 504: { | ||||
|       Result = "504 Command not implemented for that parameter.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 530: { | ||||
|       Result = "530 Not logged in.\n"; | ||||
|       break; | ||||
|     } | ||||
|     case 550: { | ||||
|       Result = "550 Requested action not taken.\n"; | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       Result = "Error msg not implemented?\n"; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   return Result; | ||||
| } | ||||
							
								
								
									
										77
									
								
								lib/ftp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								lib/ftp.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| #include <string> | ||||
| #include <cstdlib> | ||||
| #include <cstdio> | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| #include <string> | ||||
| #include "./socket.h" | ||||
| #include "./filesystem.h" | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include "./json.h" | ||||
| 
 | ||||
| namespace FTP { | ||||
|   static std::string FTPBasePath = "/tmp/mist/OnDemand/"; | ||||
|    | ||||
|   enum Mode { | ||||
|     MODE_STREAM, | ||||
|   };//FTP::Mode enumeration
 | ||||
|    | ||||
|   enum Structure { | ||||
|     STRU_FILE, | ||||
|     STRU_RECORD, | ||||
|   };//FTP::Structure enumeration
 | ||||
|    | ||||
|   enum Type { | ||||
|     TYPE_ASCII_NONPRINT, | ||||
|     TYPE_IMAGE_NONPRINT, | ||||
|   };//FTP::Type enumeration
 | ||||
|    | ||||
|   enum Commands { | ||||
|     CMD_NOCMD, | ||||
|     CMD_NOOP, | ||||
|     CMD_USER, | ||||
|     CMD_PASS, | ||||
|     CMD_QUIT, | ||||
|     CMD_PORT, | ||||
|     CMD_RETR, | ||||
|     CMD_STOR, | ||||
|     CMD_TYPE, | ||||
|     CMD_MODE, | ||||
|     CMD_STRU, | ||||
|     CMD_EPSV, | ||||
|     CMD_PASV, | ||||
|     CMD_LIST, | ||||
|     CMD_PWD, | ||||
|     CMD_CWD, | ||||
|     CMD_CDUP, | ||||
|     CMD_DELE, | ||||
|     CMD_RMD, | ||||
|     CMD_MKD, | ||||
|     CMD_RNFR, | ||||
|     CMD_RNTO, | ||||
|   };//FTP::Commands enumeration
 | ||||
|    | ||||
|   class User { | ||||
|     public: | ||||
|       User( Socket::Connection NewConnection = Socket::Connection() ); | ||||
|       ~User( ); | ||||
|       int ParseCommand( std::string Command ); | ||||
|       bool LoggedIn( ); | ||||
|       std::string NumToMsg( int MsgNum ); | ||||
|       Socket::Connection Conn; | ||||
|     private: | ||||
|       std::string USER; | ||||
|       std::string PASS; | ||||
|       Mode MODE; | ||||
|       Structure STRU; | ||||
|       Type TYPE; | ||||
|       int PORT; | ||||
|       Socket::Server Passive; | ||||
|       int MyPassivePort; | ||||
|       Filesystem::Directory MyDir; | ||||
|       std::string RNFR; | ||||
|       std::vector< std::string > ActiveStreams; | ||||
|   };//FTP::User class
 | ||||
|    | ||||
| };//FTP Namespace
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Erik Zandvliet
						Erik Zandvliet