Merge branch 'FTP' into development
Conflicts: lib/Makefile.am
This commit is contained in:
commit
b0a90b42e4
5 changed files with 829 additions and 2 deletions
|
@ -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
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
|
406
lib/ftp.cpp
Normal file
406
lib/ftp.cpp
Normal 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
79
lib/ftp.h
Normal 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
|
Loading…
Add table
Reference in a new issue