using QFtp rawcommand STOR to upload to server

86 views Asked by At

#include "client.h"
#include <QDebug>
#include <QNetworkAccessManager>
#include <QFileInfo>
QString ConvertSize(qint64 size){
    QString output("0 Bytes");
    if(size<1024){
        output=QString::number(size)+" Bytes";
        return output;
    }else if(size>1024 && size <1048576){
        double newNumber=size/1024.0;
        output=QString::number(newNumber)+" KBs";
        return output;
    }else if(size >1048576){
        double newNumber=size/1048576.0;
        output=QString::number(newNumber)+" MBs";
        return output;
    }else if(size >1073741824){
        double newNumber=size/1073741824.0;
        output=QString::number(newNumber)+" GBs";
        return output;
    }else{
        return output;
    }
}
Client::Client(QObject *parent)
    : QObject{parent}
{
    qInfo()<<this<<"constructed on: "<<QThread::currentThread();
    connect(&ftp,&QFtp::commandStarted,this,&Client::commandStarted);
    connect(&ftp,&QFtp::commandFinished,this,&Client::commandFinished);
    connect(&ftp,&QFtp::dataTransferProgress,this,&Client::dataProgress);
    connect(&ftp,&QFtp::done,this,&Client::done);
    connect(&ftp,&QFtp::listInfo,this,&Client::listInfo);
    connect(&ftp,&QFtp::stateChanged,this,&Client::stateChanged);
    connect(&ftp,&QFtp::rawCommandReply,this,&Client::rawCommandReply);


}

Client::~Client()
{
    qInfo()<<this<<"deConstructed on: "<<QThread::currentThread();
}

void Client::connectToHost(QString ip, quint16 port)
{
    qInfo()<<"connecting to    "<<ip<<":"<<port;
    ftp.connectToHost(ip,port);
    qInfo()<<"loging in";
    ftp.login("testuser","123456");

}

void Client::commandStarted(int id)
{
    //qInfo()<<"command start:"<<id;
    quint8  command=ftp.currentCommand();
    switch (command){
    case 0:qInfo()<<"command start: "<<"None";break;
    case 1:qInfo()<<"command start: "<<"SetTransferMode";break;
    case 2:qInfo()<<"command start: "<<"SetProxy";break;
    case 3:qInfo()<<"command start: "<<"ConnectToHost";break;
    case 4:qInfo()<<"command start: "<<"Login";break;
    case 5:qInfo()<<"command start: "<<"Close";break;
    case 6:qInfo()<<"command start: "<<"List";break;
    case 7:qInfo()<<"command start: "<<"Cd";break;
    case 8:qInfo()<<"command start: "<<"Get";break;
    case 9:qInfo()<<"command start: "<<"Put";break;
    case 10:qInfo()<<"command start: "<<"Remove";break;
    case 11:qInfo()<<"command start: "<<"Mkdir";break;
    case 12:qInfo()<<"command start: "<<"Rmdir";break;
    case 13:qInfo()<<"command start: "<<"Rename";break;
    case 14:qInfo()<<"command start: "<<"RawCommand";break;

    }
}

void Client::commandFinished(int id)
{
    qInfo()<<"command finished: "<<id;
    if(ftp.error()){
        qInfo()<<ftp.errorString();
    }else{
        qInfo()<<"no error";
    }
    if(ftp.currentCommand()==9){
        myfile->flush();
        myfile->close();
        myfile->deleteLater();
        myfile=NULL;
        qInfo()<<"put command ended.closing open file.";

    }
}

void Client::rawCommandReply(int code, QString detail)
{


    qInfo()<<"reply code: "<<code<<"detail: "<<detail;
    if (code==226){
        qInfo()<<"transmission ended";
    }
    if (code==150){
        qInfo()<<"serverReady";
        dataChanel();
    }
    if(code==227){
        QString ip1=detail.split("(")[1];
        QString ip2=ip1.split(")")[0];
        qInfo()<<ip2;
        QStringList data=ip2.split(",");
        QStringList ip;
        QStringList ports;

        for (int i=0;i<data.size();i++){
            if(i<4){
                ip.append(data[i]);

            }else {
                ports.append(data[i]);
            }
        }
        qInfo()<<"ip:"<<ip.join(".");
        IpPorts.append(ip.join("."));
        qInfo()<<"port:"<<ports.join("-");
        for(int i=0;i<ports.size();i++){


            IpPorts.append(ports[i]);
        }

    }
}

void Client::dataProgress(quint64 now, quint64 all)
{
    qInfo()<<"now:\t"<<ConvertSize(now)<<"\t from:\t"<<ConvertSize(all);
}

void Client::done(bool error)
{
    if (error){
        qInfo()<<"error occured when done:"<<ftp.errorString();
    }
    //ftp.close();
    qInfo()<<"ftp connection closed";


}

void Client::listInfo(const QUrlInfo &i)
{
    qInfo()<<"dir found:"<<i.name();
}

void Client::stateChanged(int state)
{

    switch(state){
    case 0:qInfo()<<"state changed: "<<"Unconnected";break;
    case 1:qInfo()<<"state changed: "<<"HostLookup";break;
    case 2:qInfo()<<"state changed: "<<"Connecting";break;
    case 3:qInfo()<<"state changed: "<<"Connected";break;
    case 4:qInfo()<<"state changed: "<<"LoggedIn";break;
    case 5:qInfo()<<"state changed: "<<"Closing";break;
    }
}



void Client::abort()
{
    ftp.abort();
    qInfo()<<"ftp connection aborted";
}

void Client::ended()
{

    qInfo()<<"ftp connection ended";

}

void Client::upload(QString &location)
{
    myfile=new QFile(location);
    if(myfile->open(QIODevice::ReadOnly)){
        ftp.rawCommand("PASV");
        ftp.rawCommand("TYPE I");
        QFileInfo fileinfo(myfile->fileName());
        qInfo()<<"size: "<<fileinfo.size();
        qInfo()<<"name: "<<fileinfo.fileName();
        qInfo()<<"uploading : "<<location;
        //qInfo()<<"file name is:"<<myfile->fileName();
        //ftp.put(myfile,fileinfo.fileName());
        QString text="STOR "+fileinfo.fileName();
        qInfo()<<text;
        ftp.rawCommand(text);
        //client.rawCommand("PASV");

        //client.rawCommand("TYPE I");
        //client.rawCommand("STAT");
        //client.rawCommand("STOR test.txt");
    }


}

void Client::list(QString &dir)
{
    qInfo()<<"listing dir:"<<dir;
    ftp.list(dir);
}

void Client::dataChanel()
{
    for(int i=0;i<IpPorts.size();i++){
        qInfo()<<IpPorts[i];
    }

    QTcpSocket* socket=new QTcpSocket(this);
    socket->connectToHost(IpPorts[0],IpPorts[1].toInt());
    QByteArray data;
    data=myfile->readAll();
    socket->waitForConnected();

    socket->write(data);
}

i need to upload files to a server and to make it resumeable i need to user raw commands and REST.

Im using QFtp raw command STOR and when it returns code 227 i parse the data and get the ip and open port then when i recieve code 150 i open a tcp port as a data socket to send the data but after a few seconds it returns the error "Data channel timed out.\r\n Win32 error: The network connection was aborted by the local system." what am i doing wrong here?how am i supposed to use this command?

1

There are 1 answers

2
Aligh2022 On BEST ANSWER

so i was reading about it and somewhere said that using PASV isnt smart and instead use EPSV to open a port.i changed my code like this and parsed the new port and changed user permissions of local ftp server to all users and it worked!

myfile=new QFile(location);
    if(myfile->open(QIODevice::ReadOnly)){
        ftp.setTransferMode(QFtp::TransferMode::Passive);
        ftp.rawCommand("TYPE I");
        ftp.rawCommand("EPSV");
        ftp.rawCommand("STAT");
        QFileInfo fileinfo(myfile->fileName());
        qInfo()<<"size: "<<fileinfo.size();
        qInfo()<<"name: "<<fileinfo.fileName();
        qInfo()<<"uploading : "<<location;
        qInfo()<<"file name is:"<<myfile->fileName();
        ftp.rawCommand("REST 1000");
        ftp.rawCommand("PWD");

        QString text="STOR "+fileinfo.fileName();
        qInfo()<<text;
        ftp.rawCommand(text);