Removed legacy libraries (converter, ftp, filesystem) from codebase.
This commit is contained in:
parent
73b1f2d75c
commit
7c0db4531d
7 changed files with 0 additions and 1393 deletions
|
@ -92,12 +92,9 @@ set(libHeaders
|
|||
${SOURCE_DIR}/lib/bitstream.h
|
||||
${SOURCE_DIR}/lib/checksum.h
|
||||
${SOURCE_DIR}/lib/config.h
|
||||
${SOURCE_DIR}/lib/converter.h
|
||||
${SOURCE_DIR}/lib/defines.h
|
||||
${SOURCE_DIR}/lib/dtsc.h
|
||||
${SOURCE_DIR}/lib/filesystem.h
|
||||
${SOURCE_DIR}/lib/flv_tag.h
|
||||
${SOURCE_DIR}/lib/ftp.h
|
||||
${SOURCE_DIR}/lib/http_parser.h
|
||||
${SOURCE_DIR}/lib/json.h
|
||||
${SOURCE_DIR}/lib/mp4_adobe.h
|
||||
|
@ -128,12 +125,9 @@ set(libSources
|
|||
${SOURCE_DIR}/lib/bitfields.cpp
|
||||
${SOURCE_DIR}/lib/bitstream.cpp
|
||||
${SOURCE_DIR}/lib/config.cpp
|
||||
${SOURCE_DIR}/lib/converter.cpp
|
||||
${SOURCE_DIR}/lib/dtsc.cpp
|
||||
${SOURCE_DIR}/lib/dtscmeta.cpp
|
||||
${SOURCE_DIR}/lib/filesystem.cpp
|
||||
${SOURCE_DIR}/lib/flv_tag.cpp
|
||||
${SOURCE_DIR}/lib/ftp.cpp
|
||||
${SOURCE_DIR}/lib/http_parser.cpp
|
||||
${SOURCE_DIR}/lib/json.cpp
|
||||
${SOURCE_DIR}/lib/mp4_adobe.cpp
|
||||
|
|
|
@ -1,328 +0,0 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "timing.h"
|
||||
#include "converter.h"
|
||||
#include "procs.h"
|
||||
#include "config.h"
|
||||
|
||||
namespace Converter {
|
||||
|
||||
///\brief The base constructor
|
||||
Converter::Converter() {
|
||||
fillFFMpegEncoders();
|
||||
}
|
||||
|
||||
///\brief A function that fill the internal variables with values provided by examing ffmpeg output
|
||||
///
|
||||
///Checks for the following encoders:
|
||||
/// - AAC
|
||||
/// - H264
|
||||
/// - MP3
|
||||
void Converter::fillFFMpegEncoders() {
|
||||
std::vector<char *> cmd;
|
||||
cmd.reserve(3);
|
||||
cmd.push_back((char *)"ffmpeg");
|
||||
cmd.push_back((char *)"-encoders");
|
||||
cmd.push_back(NULL);
|
||||
int outFD = -1;
|
||||
Util::Procs::StartPiped("FFMpegInfo", &cmd[0], 0, &outFD, 0);
|
||||
while (Util::Procs::isActive("FFMpegInfo")) {
|
||||
Util::sleep(100);
|
||||
}
|
||||
FILE * outFile = fdopen(outFD, "r");
|
||||
char * fileBuf = 0;
|
||||
size_t fileBufLen = 0;
|
||||
while (!(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)) {
|
||||
if (strstr(fileBuf, "aac") || strstr(fileBuf, "AAC")) {
|
||||
strtok(fileBuf, " \t");
|
||||
allCodecs["ffmpeg"][strtok(NULL, " \t")] = "aac";
|
||||
}
|
||||
if (strstr(fileBuf, "h264") || strstr(fileBuf, "H264")) {
|
||||
strtok(fileBuf, " \t");
|
||||
allCodecs["ffmpeg"][strtok(NULL, " \t")] = "h264";
|
||||
}
|
||||
if (strstr(fileBuf, "mp3") || strstr(fileBuf, "MP3")) {
|
||||
strtok(fileBuf, " \t");
|
||||
allCodecs["ffmpeg"][strtok(NULL, " \t")] = "mp3";
|
||||
}
|
||||
}
|
||||
fclose(outFile);
|
||||
}
|
||||
|
||||
///\brief A function to obtain all available codecs that have been obtained from the encoders.
|
||||
///\return A reference to the allCodecs member.
|
||||
converterInfo & Converter::getCodecs() {
|
||||
return allCodecs;
|
||||
}
|
||||
|
||||
///\brief A function to obtain the available encoders in JSON format.
|
||||
///\return A JSON::Value containing all encoder:codec pairs.
|
||||
JSON::Value Converter::getEncoders() {
|
||||
JSON::Value result;
|
||||
for (converterInfo::iterator convIt = allCodecs.begin(); convIt != allCodecs.end(); convIt++) {
|
||||
for (codecInfo::iterator codIt = convIt->second.begin(); codIt != convIt->second.end(); codIt++) {
|
||||
if (codIt->second == "h264") {
|
||||
result[convIt->first]["video"][codIt->first] = codIt->second;
|
||||
} else {
|
||||
result[convIt->first]["audio"][codIt->first] = codIt->second;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///\brief Looks in a given path for all files that could be converted
|
||||
///\param myPath The location to look at, this should be a folder.
|
||||
///\return A JSON::Value containing all media files in the location, with their corresponding metadata values.
|
||||
JSON::Value Converter::queryPath(std::string myPath) {
|
||||
char const * cmd[3] = {0, 0, 0};
|
||||
std::string mistPath = Util::getMyPath() + "MistInfo";
|
||||
cmd[0] = mistPath.c_str();
|
||||
JSON::Value result;
|
||||
DIR * Dirp = opendir(myPath.c_str());
|
||||
struct stat StatBuf;
|
||||
if (Dirp) {
|
||||
dirent * entry;
|
||||
while ((entry = readdir(Dirp))) {
|
||||
if (stat(std::string(myPath + "/" + entry->d_name).c_str(), &StatBuf) == -1) {
|
||||
continue;
|
||||
}
|
||||
if ((StatBuf.st_mode & S_IFREG) == 0) {
|
||||
continue;
|
||||
}
|
||||
std::string fileName = entry->d_name;
|
||||
std::string mijnPad = std::string(myPath + (myPath[myPath.size() - 1] == '/' ? "" : "/") + entry->d_name);
|
||||
cmd[1] = mijnPad.c_str();
|
||||
result[fileName] = JSON::fromString(Util::Procs::getOutputOf((char * const *)cmd));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///\brief Start a conversion with the given parameters
|
||||
///\param name The name to use for logging the conversion.
|
||||
///\param parameters The parameters, accepted are the following:
|
||||
/// - input The input url
|
||||
/// - output The output url
|
||||
/// - encoder The encoder to use
|
||||
/// - video An object containing video parameters, if not existant no video will be output. Values are:
|
||||
/// - width The width of the resulting video
|
||||
/// - height The height of the resulting video
|
||||
/// - codec The codec to encode video in, or copy to use the current codec
|
||||
/// - fpks The framerate in fps * 1000
|
||||
/// - audio An object containing audio parameters, if not existant no audio will be output. Values are:
|
||||
/// - codec The codec to encode audio in, or copy to use the current codec
|
||||
/// - samplerate The target samplerate for the audio, in hz
|
||||
void Converter::startConversion(std::string name, JSON::Value parameters) {
|
||||
if (!parameters.isMember("input")) {
|
||||
statusHistory[name] = "No input file supplied";
|
||||
return;
|
||||
}
|
||||
if (!parameters.isMember("output")) {
|
||||
statusHistory[name] = "No output file supplied";
|
||||
return;
|
||||
}
|
||||
struct stat statBuf;
|
||||
std::string outPath = parameters["output"].asString();
|
||||
outPath = outPath.substr(0, outPath.rfind('/'));
|
||||
int statRes = stat(outPath.c_str(), & statBuf);
|
||||
if (statRes == -1 || !S_ISDIR(statBuf.st_mode)) {
|
||||
statusHistory[name] = "Output path is either non-existent, or not a path.";
|
||||
return;
|
||||
}
|
||||
if (!parameters.isMember("encoder")) {
|
||||
statusHistory[name] = "No encoder specified";
|
||||
return;
|
||||
}
|
||||
if (allCodecs.find(parameters["encoder"]) == allCodecs.end()) {
|
||||
statusHistory[name] = "Can not find encoder " + parameters["encoder"].asString();
|
||||
return;
|
||||
}
|
||||
if (parameters.isMember("video")) {
|
||||
if (parameters["video"].isMember("width") && !parameters["video"].isMember("height")) {
|
||||
statusHistory[name] = "No height parameter given";
|
||||
return;
|
||||
}
|
||||
if (parameters["video"].isMember("height") && !parameters["video"].isMember("width")) {
|
||||
statusHistory[name] = "No width parameter given";
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::stringstream encoderCommand;
|
||||
if (parameters["encoder"] == "ffmpeg") {
|
||||
encoderCommand << "ffmpeg -i ";
|
||||
encoderCommand << parameters["input"].asString() << " ";
|
||||
if (parameters.isMember("video")) {
|
||||
if (!parameters["video"].isMember("codec") || parameters["video"]["codec"] == "copy") {
|
||||
encoderCommand << "-vcodec copy ";
|
||||
} else {
|
||||
codecInfo::iterator vidCodec = allCodecs["ffmpeg"].find(parameters["video"]["codec"]);
|
||||
if (vidCodec == allCodecs["ffmpeg"].end()) {
|
||||
statusHistory[name] = "Can not find video codec " + parameters["video"]["codec"].asString();
|
||||
return;
|
||||
}
|
||||
encoderCommand << "-vcodec " << vidCodec->first << " ";
|
||||
if (parameters["video"]["codec"].asString() == "h264") {
|
||||
//Enforce baseline
|
||||
encoderCommand << "-preset slow -profile:v baseline -level 30 ";
|
||||
}
|
||||
if (parameters["video"].isMember("fpks")) {
|
||||
encoderCommand << "-r " << parameters["video"]["fpks"].asInt() / 1000 << " ";
|
||||
}
|
||||
if (parameters["video"].isMember("width")) {
|
||||
encoderCommand << "-s " << parameters["video"]["width"].asInt() << "x" << parameters["video"]["height"].asInt() << " ";
|
||||
}
|
||||
///\todo Keyframe interval (different in older and newer versions of ffmpeg?)
|
||||
}
|
||||
} else {
|
||||
encoderCommand << "-vn ";
|
||||
}
|
||||
if (parameters.isMember("audio")) {
|
||||
if (!parameters["audio"].isMember("codec")) {
|
||||
encoderCommand << "-acodec copy ";
|
||||
} else {
|
||||
codecInfo::iterator audCodec = allCodecs["ffmpeg"].find(parameters["audio"]["codec"]);
|
||||
if (audCodec == allCodecs["ffmpeg"].end()) {
|
||||
statusHistory[name] = "Can not find audio codec " + parameters["audio"]["codec"].asString();
|
||||
return;
|
||||
}
|
||||
if (audCodec->second == "aac") {
|
||||
encoderCommand << "-strict -2 ";
|
||||
}
|
||||
encoderCommand << "-acodec " << audCodec->first << " ";
|
||||
if (parameters["audio"].isMember("samplerate")) {
|
||||
encoderCommand << "-ar " << parameters["audio"]["samplerate"].asInt() << " ";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
encoderCommand << "-an ";
|
||||
}
|
||||
encoderCommand << "-f flv -";
|
||||
}
|
||||
int statusFD = -1;
|
||||
Util::Procs::StartPiped2(name, encoderCommand.str(), Util::getMyPath() + "MistFLV2DTSC -o " + parameters["output"].asString(), 0, 0, &statusFD, 0);
|
||||
parameters["statusFD"] = statusFD;
|
||||
allConversions[name] = parameters;
|
||||
allConversions[name]["status"]["duration"] = "?";
|
||||
allConversions[name]["status"]["progress"] = 0;
|
||||
allConversions[name]["status"]["frame"] = 0;
|
||||
allConversions[name]["status"]["time"] = 0;
|
||||
}
|
||||
|
||||
///\brief Updates the internal status of the converter class.
|
||||
///
|
||||
///Will check for each running conversion whether it is still running, and update its status accordingly
|
||||
void Converter::updateStatus() {
|
||||
if (allConversions.size()) {
|
||||
std::map<std::string, JSON::Value>::iterator cIt;
|
||||
bool hasChanged = true;
|
||||
while (hasChanged && allConversions.size()) {
|
||||
hasChanged = false;
|
||||
for (cIt = allConversions.begin(); cIt != allConversions.end(); cIt++) {
|
||||
if (Util::Procs::isActive(cIt->first)) {
|
||||
int statusFD = dup(cIt->second["statusFD"].asInt());
|
||||
fsync(statusFD);
|
||||
FILE * statusFile = fdopen(statusFD, "r");
|
||||
char * fileBuf = 0;
|
||||
size_t fileBufLen = 0;
|
||||
fseek(statusFile, 0, SEEK_END);
|
||||
std::string line;
|
||||
int totalTime = 0;
|
||||
do {
|
||||
getdelim(&fileBuf, &fileBufLen, '\r', statusFile);
|
||||
line = fileBuf;
|
||||
if (line.find("Duration") != std::string::npos) {
|
||||
int curOffset = line.find("Duration: ") + 10;
|
||||
totalTime += atoi(line.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
|
||||
totalTime += atoi(line.substr(curOffset + 3, 2).c_str()) * 60 * 1000;
|
||||
totalTime += atoi(line.substr(curOffset + 6, 2).c_str()) * 1000;
|
||||
totalTime += atoi(line.substr(curOffset + 9, 2).c_str()) * 10;
|
||||
cIt->second["duration"] = totalTime;
|
||||
}
|
||||
} while (!feof(statusFile) && line.find("frame") != 0); //"frame" is the fist word on an actual status line of ffmpeg
|
||||
if (!feof(statusFile)) {
|
||||
cIt->second["status"] = parseFFMpegStatus(line);
|
||||
cIt->second["status"]["duration"] = cIt->second["duration"];
|
||||
cIt->second["status"]["progress"] = (cIt->second["status"]["time"].asInt() * 100) / cIt->second["duration"].asInt();
|
||||
} else {
|
||||
line.erase(line.end() - 1);
|
||||
line = line.substr(line.rfind("\n") + 1);
|
||||
cIt->second["status"] = line;
|
||||
}
|
||||
free(fileBuf);
|
||||
fclose(statusFile);
|
||||
} else {
|
||||
if (statusHistory.find(cIt->first) == statusHistory.end()) {
|
||||
statusHistory[cIt->first] = "Conversion successful, running DTSCFix";
|
||||
Util::Procs::Start(cIt->first + "DTSCFix", Util::getMyPath() + "MistDTSCFix " + cIt->second["output"].asString());
|
||||
}
|
||||
allConversions.erase(cIt);
|
||||
hasChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (statusHistory.size()) {
|
||||
std::map<std::string, std::string>::iterator sIt;
|
||||
for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++) {
|
||||
if (statusHistory[sIt->first].find("DTSCFix") != std::string::npos) {
|
||||
if (Util::Procs::isActive(sIt->first + "DTSCFIX")) {
|
||||
continue;
|
||||
}
|
||||
statusHistory[sIt->first] = "Conversion successful";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///\brief Parses a single ffmpeg status line into a JSON format
|
||||
///\param statusLine The current status of ffmpeg
|
||||
///\return A JSON::Value with the following values set:
|
||||
/// - frame The current last encoded frame
|
||||
/// - time The current last encoded timestamp
|
||||
JSON::Value Converter::parseFFMpegStatus(std::string statusLine) {
|
||||
JSON::Value result;
|
||||
int curOffset = statusLine.find("frame=") + 6;
|
||||
result["frame"] = atoi(statusLine.substr(curOffset, statusLine.find("fps=") - curOffset).c_str());
|
||||
curOffset = statusLine.find("time=") + 5;
|
||||
int myTime = 0;
|
||||
myTime += atoi(statusLine.substr(curOffset, 2).c_str()) * 60 * 60 * 1000;
|
||||
myTime += atoi(statusLine.substr(curOffset + 3, 2).c_str()) * 60 * 1000;
|
||||
myTime += atoi(statusLine.substr(curOffset + 6, 2).c_str()) * 1000;
|
||||
myTime += atoi(statusLine.substr(curOffset + 9, 2).c_str()) * 10;
|
||||
result["time"] = myTime;
|
||||
return result;
|
||||
}
|
||||
|
||||
///\brief Obtain the current internal status of the conversion class
|
||||
///\return A JSON::Value with the status of each conversion
|
||||
JSON::Value Converter::getStatus() {
|
||||
updateStatus();
|
||||
JSON::Value result;
|
||||
if (allConversions.size()) {
|
||||
for (std::map<std::string, JSON::Value>::iterator cIt = allConversions.begin(); cIt != allConversions.end(); cIt++) {
|
||||
result[cIt->first] = cIt->second["status"];
|
||||
result[cIt->first]["details"] = cIt->second;
|
||||
}
|
||||
}
|
||||
if (statusHistory.size()) {
|
||||
std::map<std::string, std::string>::iterator sIt;
|
||||
for (sIt = statusHistory.begin(); sIt != statusHistory.end(); sIt++) {
|
||||
result[sIt->first] = sIt->second;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///\brief Clears the status history of all conversions
|
||||
void Converter::clearStatus() {
|
||||
statusHistory.clear();
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
///\brief A typedef to simplify accessing all codecs
|
||||
typedef std::map<std::string, std::string> codecInfo;
|
||||
///\brief A typedef to simplify accessing all encoders
|
||||
typedef std::map<std::string, codecInfo> converterInfo;
|
||||
|
||||
///\brief A namespace containing all functions for handling the conversion API
|
||||
namespace Converter {
|
||||
|
||||
///\brief A class containing the basic conversion API functionality
|
||||
class Converter {
|
||||
public:
|
||||
Converter();
|
||||
converterInfo & getCodecs();
|
||||
JSON::Value getEncoders();
|
||||
JSON::Value queryPath(std::string myPath);
|
||||
void startConversion(std::string name, JSON::Value parameters);
|
||||
void updateStatus();
|
||||
JSON::Value getStatus();
|
||||
void clearStatus();
|
||||
JSON::Value parseFFMpegStatus(std::string statusLine);
|
||||
private:
|
||||
void fillFFMpegEncoders();
|
||||
///\brief Holds a list of all current known codecs
|
||||
converterInfo allCodecs;
|
||||
///\brief Holds a list of all the current conversions
|
||||
std::map<std::string, JSON::Value> allConversions;
|
||||
///\brief Stores the status of all conversions, and the history
|
||||
std::map<std::string, std::string> statusHistory;
|
||||
};
|
||||
}
|
|
@ -1,318 +0,0 @@
|
|||
#include "filesystem.h"
|
||||
#include "defines.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() {
|
||||
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) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "Skipping %s, reason %s", entry->d_name, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
///Convert stat to string
|
||||
Entries[std::string(entry->d_name)] = StatBuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Filesystem::Directory::Print() {
|
||||
/// \todo Remove? Libraries shouldn't print stuff.
|
||||
if (!ValidDir) {
|
||||
DEBUG_MSG(DLVL_ERROR, "%s is not a valid directory", (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());
|
||||
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 += "/";
|
||||
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())) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Removing file %s failed", 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)) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Creating directory %s failed", 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())) {
|
||||
DEBUG_MSG(DLVL_ERROR, "Renaming %s to %s failed", 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;
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
#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
|
557
lib/ftp.cpp
557
lib/ftp.cpp
|
@ -1,557 +0,0 @@
|
|||
#include "ftp.h"
|
||||
|
||||
FTP::User::User(Socket::Connection NewConnection, std::map<std::string, std::string> Credentials) {
|
||||
Conn = NewConnection;
|
||||
MyPassivePort = 0;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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: {
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()) {
|
||||
Conn.SendNow("125 Data connection already open; transfer starting.\n");
|
||||
} else {
|
||||
Conn.SendNow("150 File status okay; about to open data connection.\n");
|
||||
}
|
||||
while (!Connected.connected()) {
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string tmpstr = MyDir.LIST(ActiveStreams);
|
||||
Connected.SendNow(tmpstr);
|
||||
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);
|
||||
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;
|
||||
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.
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()) {
|
||||
Conn.SendNow("125 Data connection already open; transfer starting.\n");
|
||||
} else {
|
||||
Conn.SendNow("150 File status okay; about to open data connection.\n");
|
||||
}
|
||||
while (!Connected.connected()) {
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string tmpstr = MyDir.RETR(Command);
|
||||
Connected.SendNow(tmpstr);
|
||||
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.
|
||||
Socket::Connection Connected = Passive.accept();
|
||||
if (Connected.connected()) {
|
||||
Conn.SendNow("125 Data connection already open; transfer starting.\n");
|
||||
} else {
|
||||
Conn.SendNow("150 File status okay; about to open data connection.\n");
|
||||
}
|
||||
while (!Connected.connected()) {
|
||||
Connected = Passive.accept();
|
||||
}
|
||||
std::string Buffer;
|
||||
while (Connected.spool()) {
|
||||
}
|
||||
/// \todo Comment me back in. ^_^
|
||||
//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;
|
||||
}
|
82
lib/ftp.h
82
lib/ftp.h
|
@ -1,82 +0,0 @@
|
|||
#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, std::map<std::string, std::string> Credentials);
|
||||
~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