#include "ftpcontrolconnection.h"
#include "ftplistcommand.h"
#include "ftpretrcommand.h"
#include "ftpstorcommand.h"
#include "dataconnection.h"
#include <QFileInfo>
#include <QDateTime>
#include <QDir>
#include <QStringList>
#include <QEventLoop>
#include <QDebug>
#include <QTimer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QString>
//#include <QRegExp>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
FtpControlConnection::FtpControlConnection(QObject *parent, QTcpSocket *socket, const QString &rootPath, const QString &userName, const QString &password, bool readOnly) :
QObject(parent)
{
this->socket = socket;
this->userName = userName;
this->password = password;
this->rootPath = rootPath;
this->readOnly = readOnly;
isLoggedIn = false;
encryptDataConnection = false;
socket->setParent(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(acceptNewData()));
connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
currentDirectory = "/";
dataConnection = new DataConnection(this);
reply("220 Welcome to QFtpServer.");
}
FtpControlConnection::~FtpControlConnection()
{
}
void FtpControlConnection::acceptNewData()
{
if (!socket->canReadLine()) {
return;
}
// Note how we execute only one line, and use QTimer::singleShot, instead
// of using a for-loop until no more lines are available. This is done
// so we don't block the event loop for a long time.
processCommand(QString::fromUtf8(socket->readLine()).trimmed());
QTimer::singleShot(0, this, SLOT(acceptNewData()));
}
void FtpControlConnection::disconnectFromHost()
{
socket->disconnectFromHost();
}
bool FtpControlConnection::verifyAuthentication(const QString &command)
{
if (isLoggedIn) {
return true;
}
const char *commandsRequiringAuth[] = {
"PWD", "CWD", "TYPE", "PORT", "PASV", "LIST", "RETR", "REST",
"NLST", "SIZE", "SYST", "PROT", "CDUP", "OPTS", "PBSZ", "NOOP",
"STOR", "MKD", "RMD", "DELE", "RNFR", "RNTO", "APPE"
};
for (size_t ii = 0; ii < sizeof(commandsRequiringAuth)/sizeof(commandsRequiringAuth[0]); ++ii) {
if (command == commandsRequiringAuth[ii]) {
reply("530 You must log in first.");
return false;
}
}
return true;
}
bool FtpControlConnection::verifyWritePermission(const QString &command)
{
if (!readOnly) {
return true;
}
const char *commandsRequiringWritePermission[] = {
"STOR", "MKD", "RMD", "DELE", "RNFR", "RNTO", "APPE"
};
for (size_t ii = 0; ii < sizeof(commandsRequiringWritePermission)/sizeof(commandsRequiringWritePermission[0]); ++ii) {
if (command == commandsRequiringWritePermission[ii]) {
reply("550 Can't do that in read-only mode.");
return false;
}
}
return true;
}
QString FtpControlConnection::stripFlagL(const QString &fileName)
{
QString a = fileName.toUpper();
if (a == "-L") {
return "";
}
if (a.startsWith("-L ")) {
return fileName.mid(3);
}
return fileName;
}
void FtpControlConnection::parseCommand(const QString &entireCommand, QString *command, QString *commandParameters)
{
// Split parameters and command.
int pos = entireCommand.indexOf(' ');
if (-1 != pos) {
*command = entireCommand.left(pos).trimmed().toUpper();
*commandParameters = entireCommand.mid(pos+1).trimmed();
} else {
*command = entireCommand.trimmed().toUpper();
}
}
QString FtpControlConnection::toLocalPath(const QString &fileName) const
{
QString localPath = fileName;
// Some FTP clients send backslashes.
localPath.replace('\\', '/');
// If this is a relative path, we prepend the current directory.
if (!localPath.startsWith('/')) {
localPath = currentDirectory + '/' + localPath;
}
// Evaluate all the ".." and ".", "/path/././to/dir/../.." becomes "/path".
// Note we do this **before** prepending the root path, in order to avoid
// "jailbreaking" out of the "chroot".
QStringList components;
foreach (const QString &component, localPath.split('/', Qt::SkipEmptyParts)) {
if (component == "..") {
if (!components.isEmpty()) {
components.pop_back();
}
} else if (component != ".") {
components += component;
}
}
// Prepend the root path.
localPath = QDir::cleanPath(rootPath + '/' + components.join("/"));
qDebug() << "to local path" << fileName << "->" << localPath;
return localPath;
}
void FtpControlConnection::reply(const QString &replyCode)
{
qDebug() << "reply" << replyCode;
socket->write((replyCode + "\r\n").toUtf8());
}
void FtpControlConnection::processCommand(const QString &entireCommand)
{
qDebug() << "command" << entireCommand;
QString command;
QString commandParameters;
parseCommand(entireCommand, &command, &commandParameters);
if (!verifyAuthentication(command)) {
return;
}
if (!verifyWritePermission(command)) {
return;
}
if ("USER" == command) {
reply("331 User name OK, need password.");
} else if ("PASS" == command) {
pass(commandParameters);
} else if ("QUIT" == command) {
quit();
} else if ("AUTH" == command && "TLS" == commandParameters.toUpper()) {
auth();
} else if ("FEAT" == command) {
feat();
} else if ("PWD" == command) {
reply(QString("257 \"%1\"").arg(currentDirectory));
} else if ("CWD" == command) {
cwd(commandParameters);
} else if ("TYPE" == command) {
reply("200 Command okay.");
} else if ("PORT" == command) {
port(commandParameters);
} else if ("PASV" == command) {
pasv();
} else if ("LIST" == command) {
list(toLocalPath(stripFlagL(commandParameters)), false);
} else if ("RETR" == command) {
retr(toLocalPath(commandParameters));
} else if ("REST" == command) {
reply("350 Requested file action pending further information.");
} else if ("NLST" == command) {
list(toLocalPath(stripFlagL(commandParameters)), true);
} else if ("SIZE" == command) {
size(toLocalPath(commandParameters));
} else if ("SYST" == command) {
reply("215 UNIX");
} else if ("PROT" == command) {
prot(commandParameters.toUpper());
} else if ("CDUP" == command) {
cdup();
} else if ("OPTS" == command && "UTF8 ON" == commandParameters.toUpper()) {
reply("200 Command okay.");
} else if ("PBSZ" == command && "0" == commandParameters.toUpper()) {
reply("200 Command okay.");
} else if ("NOOP" == command) {
reply("200 Command okay.");
} else if ("STOR" == command) {
stor(toLocalPath(commandParameters));
} else if ("MKD" == command) {
mkd(toLocalPath(commandParameters));
} else if ("RMD" == command) {
rmd(toLocalPath(commandParameters));
} else if ("DELE" == command) {
dele(toLocalPath(commandParameters));
} else if ("RNFR" == command) {
reply("350 Requested file action pending further information.");
} else if ("RNTO" == command) {
rnto(toLocalPath(commandParameters));
} else if ("APPE" == command) {
stor(toLocalPath(commandParameters), true);
} else {
reply("502 Command not implemented.");
}
lastProcessedCommand = entireCommand;
}
void FtpControlConnection::startOrScheduleCommand(FtpCommand *ftpCommand)
{
connect(ftpCommand, SIGNAL(reply(QString)), this, SLOT(reply(QString)));
if (!dataConnection->setFtpComman
小灰灰搞电子
- 粉丝: 4w+
- 资源: 108
最新资源
- C# 西门子S7 TCP协议客户端设计工程源码带注释,开源dll文件,包括打包完的安装包
- 电网行测冲刺讲义-学生版-纯图版
- 基于磁链锁相环控制的双向逆变器Simulink仿真,无需 电压采样进行锁相控制
- 工程管理:长沙理工大学2021级工程造价咨询综合实践指导-课程设计实施方案及细则
- 黑龙江省各市、县、区及街镇网页版SVG图
- json-c-0.17.tar.gz
- 前端全套面试题资料,包含js、css、vue等相关资料
- C#上位机 APP监控西门子S7-1200 C#全套源代码 1,C#开发上位机手机APP,自己写的程序可提供部分 2,通过VS2019开发安卓手机app 3,全套源代码,现场运行设备实测有效 4
- 综合能源耦合微网优化程序matlab 程序基于冷热电联供综合能源耦合模型,采用cchp,并且含有压缩空气储能,采用粒子群优化求解
- 2025电网行测基础讲义-学生版-纯图版
- chromedriver-win64_133.0.6939.0.zip
- chromedriver-win64_133.0.6941.0.zip
- FOC电机控制,一份基于国产风机量产程序,包含龙博格电机状态观测器,SVPWM,顺逆风启动,五段式与七段式调制等源码,完全可以移植到别的MCU平台 适合电机算法研究
- chromedriver-win64_133.0.6943.2.zip
- chromedriver-win64_133.0.6942.0.zip
- chromedriver-win64_133.0.6943.0.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
评论4