Merge branch 'FTP' into development

Conflicts:
	lib/Makefile.am
This commit is contained in:
Thulinma 2012-09-03 10:21:40 +02:00
commit b0a90b42e4
5 changed files with 829 additions and 2 deletions

View file

@ -1,7 +1,7 @@
AM_CPPFLAGS = $(global_CFLAGS)
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 stream.h stream.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 stream.h stream.cpp
libmist_1_0_la_LIBADD=-lssl -lcrypto
libmist_1_0_la_LDFLAGS = -version-info 1:0:0
@ -9,4 +9,4 @@ 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 stream.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 stream.h

273
lib/filesystem.cpp Normal file
View 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
View 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

406
lib/ftp.cpp Normal file
View file

@ -0,0 +1,406 @@
#include "ftp.h"
FTP::User::User( Socket::Connection NewConnection, std::map<std::string,std::string> Credentials ) {
Conn = NewConnection;
USER = "";
PASS = "";
MODE = MODE_STREAM;
STRU = STRU_FILE;
TYPE = TYPE_ASCII_NONPRINT;
PORT = 20;
RNFR = "";
AllCredentials = Credentials;
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 = Command;
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 = Command;
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.Send( "125 Data connection already open; transfer starting.\n" );
} else {
Conn.Send( "150 File status okay; about to open data connection.\n" );
}
while( !Connected.connected() ) {
Connected = Passive.accept();
}
fprintf( stderr, "Sending LIST information\n" );
Connected.Send( 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.Send( "125 Data connection already open; transfer starting.\n" );
} else {
Conn.Send( "150 File status okay; about to open data connection.\n" );
}
while( !Connected.connected() ) {
Connected = Passive.accept();
}
fprintf( stderr, "Sending RETR information\n" );
Connected.Send( 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.Send( "125 Data connection already open; transfer starting.\n" );
} else {
Conn.Send( "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; }
if( !AllCredentials.size() ) {
return true;
}
if( ( AllCredentials.find( USER ) != AllCredentials.end() ) && AllCredentials[USER] == PASS ) {
return true;
}
return false;
}
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;
}

79
lib/ftp.h Normal file
View file

@ -0,0 +1,79 @@
#include <map>
#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(), std::map<std::string,std::string> Credentials = std::map<std::string,std::string>() );
~User( );
int ParseCommand( std::string Command );
bool LoggedIn( );
std::string NumToMsg( int MsgNum );
Socket::Connection Conn;
private:
std::map<std::string,std::string> AllCredentials;
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