123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469 |
-
- #include "qftp.h"
- #include "qabstractsocket.h"
- #include "qcoreapplication.h"
- #include "qtcpsocket.h"
- #include "qstringlist.h"
- #include "qregexp.h"
- #include "qtimer.h"
- #include "qfileinfo.h"
- #include "qtcpserver.h"
- #include "qlocale.h"
- QT_BEGIN_NAMESPACE
- class QFtpPI;
- class QFtpDTP : public QObject
- {
- Q_OBJECT
- public:
- enum ConnectState {
- CsHostFound,
- CsConnected,
- CsClosed,
- CsHostNotFound,
- CsConnectionRefused
- };
- QFtpDTP(QFtpPI *p, QObject *parent = nullptr);
- void setData(QByteArray *);
- void setDevice(QIODevice *);
- void writeData();
- void setBytesTotal(qint64 bytes);
- bool hasError() const;
- QString errorMessage() const;
- void clearError();
- void connectToHost(const QString & host, quint16 port);
- int setupListener(const QHostAddress &address);
- void waitForConnection();
- QTcpSocket::SocketState state() const;
- qint64 bytesAvailable() const;
- qint64 read(char *data, qint64 maxlen);
- QByteArray readAll();
- void abortConnection();
- static bool parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info);
- signals:
- void listInfo(const QUrlInfo&);
- void readyRead();
- void dataTransferProgress(qint64, qint64);
- void connectState(int);
- private slots:
- void socketConnected();
- void socketReadyRead();
- void socketError(QAbstractSocket::SocketError);
- void socketConnectionClosed();
- void socketBytesWritten(qint64);
- void setupSocket();
- void dataReadyRead();
- private:
- void clearData();
- QTcpSocket *socket;
- QTcpServer listener;
- QFtpPI *pi;
- QString err;
- qint64 bytesDone;
- qint64 bytesTotal;
- bool callWriteData;
-
-
- union {
- QByteArray *ba;
- QIODevice *dev;
- } data;
- bool is_ba;
- QByteArray bytesFromSocket;
- };
- class QFtpPI : public QObject
- {
- Q_OBJECT
- public:
- QFtpPI(QObject *parent = nullptr);
- void connectToHost(const QString &host, quint16 port);
- bool sendCommands(const QStringList &cmds);
- bool sendCommand(const QString &cmd)
- { return sendCommands(QStringList(cmd)); }
- void clearPendingCommands();
- void abort();
- QString currentCommand() const
- { return currentCmd; }
- bool rawCommand;
- bool transferConnectionExtended;
- QFtpDTP dtp;
-
- signals:
- void connectState(int);
- void finished(const QString&);
- void error(int, const QString&);
- void rawFtpReply(int, const QString&);
- private slots:
- void hostFound();
- void connected();
- void connectionClosed();
- void delayedCloseFinished();
- void readyRead();
- void error(QAbstractSocket::SocketError);
- void dtpConnectState(int);
- private:
-
-
- enum State {
- Begin,
- Idle,
- Waiting,
- Success,
- Failure
- };
- enum AbortState {
- None,
- AbortStarted,
- WaitForAbortToFinish
- };
- bool processReply();
- bool startNextCmd();
- QTcpSocket commandSocket;
- QString replyText;
- char replyCode[3];
- State state;
- AbortState abortState;
- QStringList pendingCommands;
- QString currentCmd;
- bool waitForDtpToConnect;
- bool waitForDtpToClose;
- QByteArray bytesFromSocket;
- friend class QFtpDTP;
- };
- class QFtpCommand
- {
- public:
- QFtpCommand(QFtp::Command cmd, const QStringList &raw, const QByteArray &ba);
- QFtpCommand(QFtp::Command cmd, const QStringList &raw, QIODevice *dev = nullptr);
- ~QFtpCommand();
- int id;
- QFtp::Command command;
- QStringList rawCmds;
-
-
- union {
- QByteArray *ba;
- QIODevice *dev;
- } data;
- bool is_ba;
- };
- static int nextId()
- {
- static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
- return 1 + counter.fetchAndAddRelaxed(1);
- }
- QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, const QByteArray &ba)
- : command(cmd), rawCmds(raw), is_ba(true)
- {
- id = nextId();
- data.ba = new QByteArray(ba);
- }
- QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, QIODevice *dev)
- : command(cmd), rawCmds(raw), is_ba(false)
- {
- id = nextId();
- data.dev = dev;
- }
- QFtpCommand::~QFtpCommand()
- {
- if (is_ba)
- delete data.ba;
- }
- QFtpDTP::QFtpDTP(QFtpPI *p, QObject *parent) :
- QObject(parent),
- socket(nullptr),
- listener(this),
- pi(p),
- callWriteData(false)
- {
- clearData();
- listener.setObjectName(QLatin1String("QFtpDTP active state server"));
- connect(&listener, SIGNAL(newConnection()), SLOT(setupSocket()));
- }
- void QFtpDTP::setData(QByteArray *ba)
- {
- is_ba = true;
- data.ba = ba;
- }
- void QFtpDTP::setDevice(QIODevice *dev)
- {
- is_ba = false;
- data.dev = dev;
- }
- void QFtpDTP::setBytesTotal(qint64 bytes)
- {
- bytesTotal = bytes;
- bytesDone = 0;
- emit dataTransferProgress(bytesDone, bytesTotal);
- }
- void QFtpDTP::connectToHost(const QString & host, quint16 port)
- {
- bytesFromSocket.clear();
- if (socket) {
- delete socket;
- socket = nullptr;
- }
- socket = new QTcpSocket(this);
- #ifndef QT_NO_BEARERMANAGEMENT
-
- socket->setProperty("_q_networksession", property("_q_networksession"));
- #endif
- socket->setObjectName(QLatin1String("QFtpDTP Passive state socket"));
- connect(socket, SIGNAL(connected()), SLOT(socketConnected()));
- connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
- connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)));
- connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed()));
- connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
- socket->connectToHost(host, port);
- }
- int QFtpDTP::setupListener(const QHostAddress &address)
- {
- #ifndef QT_NO_BEARERMANAGEMENT
-
- listener.setProperty("_q_networksession", property("_q_networksession"));
- #endif
- if (!listener.isListening() && !listener.listen(address, 0))
- return -1;
- return listener.serverPort();
- }
- void QFtpDTP::waitForConnection()
- {
-
-
-
- if (listener.isListening())
- listener.waitForNewConnection();
- }
- QTcpSocket::SocketState QFtpDTP::state() const
- {
- return socket ? socket->state() : QTcpSocket::UnconnectedState;
- }
- qint64 QFtpDTP::bytesAvailable() const
- {
- if (!socket || socket->state() != QTcpSocket::ConnectedState)
- return (qint64) bytesFromSocket.size();
- return socket->bytesAvailable();
- }
- qint64 QFtpDTP::read(char *data, qint64 maxlen)
- {
- qint64 read;
- if (socket && socket->state() == QTcpSocket::ConnectedState) {
- read = socket->read(data, maxlen);
- } else {
- read = qMin(maxlen, qint64(bytesFromSocket.size()));
- memcpy(data, bytesFromSocket.data(), read);
- bytesFromSocket.remove(0, read);
- }
- bytesDone += read;
- return read;
- }
- QByteArray QFtpDTP::readAll()
- {
- QByteArray tmp;
- if (socket && socket->state() == QTcpSocket::ConnectedState) {
- tmp = socket->readAll();
- bytesDone += tmp.size();
- } else {
- tmp = bytesFromSocket;
- bytesFromSocket.clear();
- }
- return tmp;
- }
- void QFtpDTP::writeData()
- {
- if (!socket)
- return;
- if (is_ba) {
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::writeData: write %d bytes", data.ba->size());
- #endif
- if (data.ba->size() == 0)
- emit dataTransferProgress(0, bytesTotal);
- else
- socket->write(data.ba->data(), data.ba->size());
- socket->close();
- clearData();
- } else if (data.dev) {
- callWriteData = false;
- const qint64 blockSize = 16*1024;
- char buf[16*1024];
- qint64 read = data.dev->read(buf, blockSize);
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::writeData: write() of size %lli bytes", read);
- #endif
- if (read > 0) {
- socket->write(buf, read);
- } else if (read == -1 || (!data.dev->isSequential() && data.dev->atEnd())) {
-
- if (bytesDone == 0 && socket->bytesToWrite() == 0)
- emit dataTransferProgress(0, bytesTotal);
- socket->close();
- clearData();
- }
-
- callWriteData = data.dev != nullptr;
- }
- }
- void QFtpDTP::dataReadyRead()
- {
- writeData();
- }
- inline bool QFtpDTP::hasError() const
- {
- return !err.isNull();
- }
- inline QString QFtpDTP::errorMessage() const
- {
- return err;
- }
- inline void QFtpDTP::clearError()
- {
- err.clear();
- }
- void QFtpDTP::abortConnection()
- {
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::abortConnection, bytesAvailable == %lli",
- socket ? socket->bytesAvailable() : (qint64) 0);
- #endif
- callWriteData = false;
- clearData();
- if (socket)
- socket->abort();
- }
- static void _q_fixupDateTime(QDateTime *dateTime)
- {
-
- const int futureTolerance = 86400;
- if (dateTime->secsTo(QDateTime::currentDateTime()) < -futureTolerance) {
- QDate d = dateTime->date();
- d.setDate(d.year() - 1, d.month(), d.day());
- dateTime->setDate(d);
- }
- }
- static void _q_parseUnixDir(const QStringList &tokens, const QString &userName, QUrlInfo *info)
- {
-
-
-
-
- if (tokens.size() != 8)
- return;
- char first = tokens.at(1).at(0).toLatin1();
- if (first == 'd') {
- info->setDir(true);
- info->setFile(false);
- info->setSymLink(false);
- } else if (first == '-') {
- info->setDir(false);
- info->setFile(true);
- info->setSymLink(false);
- } else if (first == 'l') {
- info->setDir(true);
- info->setFile(false);
- info->setSymLink(true);
- }
-
- QString name = tokens.at(7);
- if (info->isSymLink()) {
- int linkPos = name.indexOf(QLatin1String(" ->"));
- if (linkPos != -1)
- name.resize(linkPos);
- }
- info->setName(name);
-
- info->setOwner(tokens.at(3));
- info->setGroup(tokens.at(4));
-
- info->setSize(tokens.at(5).toLongLong());
- QStringList formats;
- formats << QLatin1String("MMM dd yyyy") << QLatin1String("MMM dd hh:mm") << QLatin1String("MMM d yyyy")
- << QLatin1String("MMM d hh:mm") << QLatin1String("MMM d yyyy") << QLatin1String("MMM dd yyyy");
- QString dateString = tokens.at(6);
- dateString[0] = dateString[0].toUpper();
-
- QDateTime dateTime;
- int n = 0;
- #ifndef QT_NO_DATESTRING
- do {
- dateTime = QLocale::c().toDateTime(dateString, formats.at(n++));
- } while (n < formats.size() && (!dateTime.isValid()));
- #endif
- if (n == 2 || n == 4) {
-
- dateTime.setDate(QDate(QDate::currentDate().year(),
- dateTime.date().month(),
- dateTime.date().day()));
- _q_fixupDateTime(&dateTime);
- }
- if (dateTime.isValid())
- info->setLastModified(dateTime);
-
- int permissions = 0;
- const QString &p = tokens.at(2);
- permissions |= (p[0] == QLatin1Char('r') ? QUrlInfo::ReadOwner : 0);
- permissions |= (p[1] == QLatin1Char('w') ? QUrlInfo::WriteOwner : 0);
- permissions |= (p[2] == QLatin1Char('x') ? QUrlInfo::ExeOwner : 0);
- permissions |= (p[3] == QLatin1Char('r') ? QUrlInfo::ReadGroup : 0);
- permissions |= (p[4] == QLatin1Char('w') ? QUrlInfo::WriteGroup : 0);
- permissions |= (p[5] == QLatin1Char('x') ? QUrlInfo::ExeGroup : 0);
- permissions |= (p[6] == QLatin1Char('r') ? QUrlInfo::ReadOther : 0);
- permissions |= (p[7] == QLatin1Char('w') ? QUrlInfo::WriteOther : 0);
- permissions |= (p[8] == QLatin1Char('x') ? QUrlInfo::ExeOther : 0);
- info->setPermissions(permissions);
- bool isOwner = info->owner() == userName;
- info->setReadable((permissions & QUrlInfo::ReadOther) || ((permissions & QUrlInfo::ReadOwner) && isOwner));
- info->setWritable((permissions & QUrlInfo::WriteOther) || ((permissions & QUrlInfo::WriteOwner) && isOwner));
- }
- static void _q_parseDosDir(const QStringList &tokens, const QString &userName, QUrlInfo *info)
- {
-
-
-
- if (tokens.size() != 4)
- return;
- Q_UNUSED(userName);
- QString name = tokens.at(3);
- info->setName(name);
- info->setSymLink(name.endsWith(QLatin1String(".lnk"), Qt::CaseInsensitive));
- if (tokens.at(2) == QLatin1String("<DIR>")) {
- info->setFile(false);
- info->setDir(true);
- } else {
- info->setFile(true);
- info->setDir(false);
- info->setSize(tokens.at(2).toLongLong());
- }
-
-
- int permissions = QUrlInfo::ReadOwner | QUrlInfo::WriteOwner
- | QUrlInfo::ReadGroup | QUrlInfo::WriteGroup
- | QUrlInfo::ReadOther | QUrlInfo::WriteOther;
- QStringRef ext;
- int extIndex = name.lastIndexOf(QLatin1Char('.'));
- if (extIndex != -1)
- ext = name.midRef(extIndex + 1);
- if (ext == QLatin1String("exe") || ext == QLatin1String("bat") || ext == QLatin1String("com"))
- permissions |= QUrlInfo::ExeOwner | QUrlInfo::ExeGroup | QUrlInfo::ExeOther;
- info->setPermissions(permissions);
- info->setReadable(true);
- info->setWritable(info->isFile());
- QDateTime dateTime;
- #ifndef QT_NO_DATESTRING
- dateTime = QLocale::c().toDateTime(tokens.at(1), QLatin1String("MM-dd-yy hh:mmAP"));
- if (dateTime.date().year() < 1971) {
- dateTime.setDate(QDate(dateTime.date().year() + 100,
- dateTime.date().month(),
- dateTime.date().day()));
- }
- #endif
- info->setLastModified(dateTime);
- }
- bool QFtpDTP::parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info)
- {
- if (buffer.isEmpty())
- return false;
- QString bufferStr = QString::fromUtf8(buffer).trimmed();
-
- QRegExp unixPattern(QLatin1String("^([\\-dl])([a-zA-Z\\-]{9,9})\\s+\\d+\\s+(\\S*)\\s+"
- "(\\S*)\\s+(\\d+)\\s+(\\S+\\s+\\S+\\s+\\S+)\\s+(\\S.*)"));
- if (unixPattern.indexIn(bufferStr) == 0) {
- _q_parseUnixDir(unixPattern.capturedTexts(), userName, info);
- return true;
- }
-
- QRegExp dosPattern(QLatin1String("^(\\d\\d-\\d\\d-\\d\\d\\ \\ \\d\\d:\\d\\d[AP]M)\\s+"
- "(<DIR>|\\d+)\\s+(\\S.*)$"));
- if (dosPattern.indexIn(bufferStr) == 0) {
- _q_parseDosDir(dosPattern.capturedTexts(), userName, info);
- return true;
- }
-
- return false;
- }
- void QFtpDTP::socketConnected()
- {
- bytesDone = 0;
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsConnected)");
- #endif
- emit connectState(QFtpDTP::CsConnected);
- }
- void QFtpDTP::socketReadyRead()
- {
- if (!socket)
- return;
- if (pi->currentCommand().isEmpty()) {
- socket->close();
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsClosed)");
- #endif
- emit connectState(QFtpDTP::CsClosed);
- return;
- }
- if (pi->abortState != QFtpPI::None) {
-
- socket->readAll();
- return;
- }
- if (pi->currentCommand().startsWith(QLatin1String("LIST"))) {
- while (socket->canReadLine()) {
- QUrlInfo i;
- QByteArray line = socket->readLine();
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP read (list): '%s'", line.constData());
- #endif
- if (parseDir(line, QLatin1String(""), &i)) {
- emit listInfo(i);
- } else {
-
-
-
- if (line.endsWith("No such file or directory\r\n"))
- err = QString::fromUtf8(line);
- }
- }
- } else {
- if (!is_ba && data.dev) {
- do {
- QByteArray ba;
- ba.resize(socket->bytesAvailable());
- qint64 bytesRead = socket->read(ba.data(), ba.size());
- if (bytesRead < 0) {
-
-
- return;
- }
- ba.resize(bytesRead);
- bytesDone += bytesRead;
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP read: %lli bytes (total %lli bytes)", bytesRead, bytesDone);
- #endif
- if (data.dev)
- data.dev->write(ba);
- emit dataTransferProgress(bytesDone, bytesTotal);
-
-
-
- } while (socket->bytesAvailable());
- } else {
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP readyRead: %lli bytes available (total %lli bytes read)",
- bytesAvailable(), bytesDone);
- #endif
- emit dataTransferProgress(bytesDone+socket->bytesAvailable(), bytesTotal);
- emit readyRead();
- }
- }
- }
- void QFtpDTP::socketError(QAbstractSocket::SocketError e)
- {
- if (e == QTcpSocket::HostNotFoundError) {
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsHostNotFound)");
- #endif
- emit connectState(QFtpDTP::CsHostNotFound);
- } else if (e == QTcpSocket::ConnectionRefusedError) {
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsConnectionRefused)");
- #endif
- emit connectState(QFtpDTP::CsConnectionRefused);
- }
- }
- void QFtpDTP::socketConnectionClosed()
- {
- if (!is_ba && data.dev) {
- clearData();
- }
- if (socket->isOpen())
- bytesFromSocket = socket->readAll();
- else
- bytesFromSocket.clear();
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsClosed)");
- #endif
- emit connectState(QFtpDTP::CsClosed);
- }
- void QFtpDTP::socketBytesWritten(qint64 bytes)
- {
- bytesDone += bytes;
- #if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::bytesWritten(%lli)", bytesDone);
- #endif
- emit dataTransferProgress(bytesDone, bytesTotal);
- if (callWriteData)
- writeData();
- }
- void QFtpDTP::setupSocket()
- {
- socket = listener.nextPendingConnection();
- socket->setObjectName(QLatin1String("QFtpDTP Active state socket"));
- connect(socket, SIGNAL(connected()), SLOT(socketConnected()));
- connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
- connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)));
- connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed()));
- connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
- listener.close();
- }
- void QFtpDTP::clearData()
- {
- is_ba = false;
- data.dev = nullptr;
- }
- QFtpPI::QFtpPI(QObject *parent) :
- QObject(parent),
- rawCommand(false),
- transferConnectionExtended(true),
- dtp(this),
- commandSocket(nullptr),
- state(Begin), abortState(None),
- currentCmd(QString()),
- waitForDtpToConnect(false),
- waitForDtpToClose(false)
- {
- commandSocket.setObjectName(QLatin1String("QFtpPI_socket"));
- connect(&commandSocket, SIGNAL(hostFound()),
- SLOT(hostFound()));
- connect(&commandSocket, SIGNAL(connected()),
- SLOT(connected()));
- connect(&commandSocket, SIGNAL(disconnected()),
- SLOT(connectionClosed()));
- connect(&commandSocket, SIGNAL(readyRead()),
- SLOT(readyRead()));
- connect(&commandSocket, SIGNAL(error(QAbstractSocket::SocketError)),
- SLOT(error(QAbstractSocket::SocketError)));
- connect(&dtp, SIGNAL(connectState(int)),
- SLOT(dtpConnectState(int)));
- }
- void QFtpPI::connectToHost(const QString &host, quint16 port)
- {
- emit connectState(QFtp::HostLookup);
- #ifndef QT_NO_BEARERMANAGEMENT
-
- commandSocket.setProperty("_q_networksession", property("_q_networksession"));
- dtp.setProperty("_q_networksession", property("_q_networksession"));
- #endif
- commandSocket.connectToHost(host, port);
- }
- bool QFtpPI::sendCommands(const QStringList &cmds)
- {
- if (!pendingCommands.isEmpty())
- return false;
- if (commandSocket.state() != QTcpSocket::ConnectedState || state!=Idle) {
- emit error(QFtp::NotConnected, QFtp::tr("Not connected"));
- return true;
- }
- pendingCommands = cmds;
- startNextCmd();
- return true;
- }
- void QFtpPI::clearPendingCommands()
- {
- pendingCommands.clear();
- dtp.abortConnection();
- currentCmd.clear();
- state = Idle;
- }
- void QFtpPI::abort()
- {
- pendingCommands.clear();
- if (abortState != None)
-
- return;
- if (currentCmd.isEmpty())
- return;
- if (currentCmd.startsWith(QLatin1String("STOR "))) {
- abortState = AbortStarted;
- #if defined(QFTPPI_DEBUG)
- qDebug("QFtpPI send: ABOR");
- #endif
- commandSocket.write("ABOR\r\n", 6);
- dtp.abortConnection();
- } else {
-
-
-
-
- abortState = WaitForAbortToFinish;
- dtp.abortConnection();
- }
- }
- void QFtpPI::hostFound()
- {
- emit connectState(QFtp::Connecting);
- }
- void QFtpPI::connected()
- {
- state = Begin;
- #if defined(QFTPPI_DEBUG)
- #endif
-
- commandSocket.setSocketOption(QAbstractSocket::LowDelayOption, 1);
- emit connectState(QFtp::Connected);
- }
- void QFtpPI::connectionClosed()
- {
- commandSocket.close();
- emit connectState(QFtp::Unconnected);
- }
- void QFtpPI::delayedCloseFinished()
- {
- emit connectState(QFtp::Unconnected);
- }
- void QFtpPI::error(QAbstractSocket::SocketError e)
- {
- if (e == QTcpSocket::HostNotFoundError) {
- emit connectState(QFtp::Unconnected);
- emit error(QFtp::HostNotFound,
- QFtp::tr("Host %1 not found").arg(commandSocket.peerName()));
- } else if (e == QTcpSocket::ConnectionRefusedError) {
- emit connectState(QFtp::Unconnected);
- emit error(QFtp::ConnectionRefused,
- QFtp::tr("Connection refused to host %1").arg(commandSocket.peerName()));
- } else if (e == QTcpSocket::SocketTimeoutError) {
- emit connectState(QFtp::Unconnected);
- emit error(QFtp::ConnectionRefused,
- QFtp::tr("Connection timed out to host %1").arg(commandSocket.peerName()));
- }
- }
- void QFtpPI::readyRead()
- {
- if (waitForDtpToClose)
- return;
- while (commandSocket.canReadLine()) {
-
- QString line = QString::fromUtf8(commandSocket.readLine());
- if (replyText.isEmpty()) {
- if (line.length() < 3) {
-
- return;
- }
- const int lowerLimit[3] = {1,0,0};
- const int upperLimit[3] = {5,5,9};
- for (int i=0; i<3; i++) {
- replyCode[i] = line.at(i).digitValue();
- if (replyCode[i]<lowerLimit[i] || replyCode[i]>upperLimit[i]) {
-
- return;
- }
- }
- }
- const char count[4] = { char('0' + replyCode[0]), char('0' + replyCode[1]),
- char('0' + replyCode[2]), char(' ') };
- QString endOfMultiLine(QLatin1String(count, 4));
- QString lineCont(endOfMultiLine);
- lineCont[3] = QLatin1Char('-');
- QStringRef lineLeft4 = line.leftRef(4);
- while (lineLeft4 != endOfMultiLine) {
- if (lineLeft4 == lineCont)
- replyText += line.midRef(4);
- else
- replyText += line;
- if (!commandSocket.canReadLine())
- return;
- line = QString::fromUtf8(commandSocket.readLine());
- lineLeft4 = line.leftRef(4);
- }
- replyText += line.midRef(4);
- if (replyText.endsWith(QLatin1String("\r\n")))
- replyText.chop(2);
- if (processReply())
- replyText = QLatin1String("");
- }
- }
- bool QFtpPI::processReply()
- {
- #if defined(QFTPPI_DEBUG)
- if (replyText.length() < 400)
- qDebug("QFtpPI recv: %d %s", 100*replyCode[0]+10*replyCode[1]+replyCode[2], replyText.toLatin1().constData());
- else
- qDebug("QFtpPI recv: %d (text skipped)", 100*replyCode[0]+10*replyCode[1]+replyCode[2]);
- #endif
- int replyCodeInt = 100*replyCode[0] + 10*replyCode[1] + replyCode[2];
-
-
- if (replyCodeInt == 226 || (replyCodeInt == 250 && currentCmd.startsWith(QLatin1String("RETR")))) {
- if (dtp.state() != QTcpSocket::UnconnectedState) {
- waitForDtpToClose = true;
- return false;
- }
- }
- switch (abortState) {
- case AbortStarted:
- abortState = WaitForAbortToFinish;
- break;
- case WaitForAbortToFinish:
- abortState = None;
- return true;
- default:
- break;
- }
-
- static const State table[5] = {
-
- Waiting, Success, Idle, Failure, Failure
- };
- switch (state) {
- case Begin:
- if (replyCode[0] == 1) {
- return true;
- } else if (replyCode[0] == 2) {
- state = Idle;
- emit finished(QFtp::tr("Connected to host %1").arg(commandSocket.peerName()));
- break;
- }
-
- return true;
- case Waiting:
- if (static_cast<signed char>(replyCode[0]) < 0 || replyCode[0] > 5)
- state = Failure;
- else
- if (replyCodeInt == 202)
- state = Failure;
- else
- state = table[replyCode[0] - 1];
- break;
- default:
-
- return true;
- }
- #if defined(QFTPPI_DEBUG)
- #endif
-
- emit rawFtpReply(replyCodeInt, replyText);
- if (rawCommand) {
- rawCommand = false;
- } else if (replyCodeInt == 227) {
-
-
-
-
-
- QRegExp addrPortPattern(QLatin1String("(\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)"));
- if (addrPortPattern.indexIn(replyText) == -1) {
- #if defined(QFTPPI_DEBUG)
- qDebug("QFtp: bad 227 response -- address and port information missing");
- #endif
-
- } else {
- const QStringList lst = addrPortPattern.capturedTexts();
- QString host = lst[1] + QLatin1Char('.') + lst[2] + QLatin1Char('.') + lst[3] + QLatin1Char('.') + lst[4];
- quint16 port = (lst[5].toUInt() << 8) + lst[6].toUInt();
- waitForDtpToConnect = true;
- dtp.connectToHost(host, port);
- }
- } else if (replyCodeInt == 229) {
-
- int portPos = replyText.indexOf(QLatin1Char('('));
- if (portPos == -1) {
- #if defined(QFTPPI_DEBUG)
- qDebug("QFtp: bad 229 response -- port information missing");
- #endif
-
- } else {
- ++portPos;
- QChar delimiter = replyText.at(portPos);
- const auto epsvParameters = replyText.midRef(portPos).split(delimiter);
- waitForDtpToConnect = true;
- dtp.connectToHost(commandSocket.peerAddress().toString(),
- epsvParameters.at(3).toInt());
- }
- } else if (replyCodeInt == 230) {
- if (currentCmd.startsWith(QLatin1String("USER ")) && pendingCommands.count()>0 &&
- pendingCommands.constFirst().startsWith(QLatin1String("PASS "))) {
-
- pendingCommands.pop_front();
- }
-
- emit connectState(QFtp::LoggedIn);
- } else if (replyCodeInt == 213) {
-
- if (currentCmd.startsWith(QLatin1String("SIZE ")))
- dtp.setBytesTotal(replyText.simplified().toLongLong());
- } else if (replyCode[0]==1 && currentCmd.startsWith(QLatin1String("STOR "))) {
- dtp.waitForConnection();
- dtp.writeData();
- }
-
- switch (state) {
- case Begin:
-
- break;
- case Success:
-
- state = Idle;
- case Idle:
- if (dtp.hasError()) {
- emit error(QFtp::UnknownError, dtp.errorMessage());
- dtp.clearError();
- }
- startNextCmd();
- break;
- case Waiting:
-
- break;
- case Failure:
-
-
- if (currentCmd.startsWith(QLatin1String("EPSV"))) {
- transferConnectionExtended = false;
- pendingCommands.prepend(QLatin1String("PASV\r\n"));
- } else if (currentCmd.startsWith(QLatin1String("EPRT"))) {
- transferConnectionExtended = false;
- pendingCommands.prepend(QLatin1String("PORT\r\n"));
- } else {
- emit error(QFtp::UnknownError, replyText);
- }
- if (state != Waiting) {
- state = Idle;
- startNextCmd();
- }
- break;
- }
- #if defined(QFTPPI_DEBUG)
- #endif
- return true;
- }
- bool QFtpPI::startNextCmd()
- {
- if (waitForDtpToConnect)
-
- return true;
- #if defined(QFTPPI_DEBUG)
- if (state != Idle)
- qDebug("QFtpPI startNextCmd: Internal error! QFtpPI called in non-Idle state %d", state);
- #endif
- if (pendingCommands.isEmpty()) {
- currentCmd.clear();
- emit finished(replyText);
- return false;
- }
- currentCmd = pendingCommands.constFirst();
-
-
-
-
- QHostAddress address = commandSocket.localAddress();
- if (currentCmd.startsWith(QLatin1String("PORT"))) {
- if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended) {
- int port = dtp.setupListener(address);
- currentCmd = QLatin1String("EPRT |");
- currentCmd += (address.protocol() == QTcpSocket::IPv4Protocol) ? QLatin1Char('1') : QLatin1Char('2');
- currentCmd += QLatin1Char('|') + address.toString() + QLatin1Char('|') + QString::number(port);
- currentCmd += QLatin1Char('|');
- } else if (address.protocol() == QTcpSocket::IPv4Protocol) {
- int port = dtp.setupListener(address);
- QString portArg;
- quint32 ip = address.toIPv4Address();
- portArg += QString::number((ip & 0xff000000) >> 24);
- portArg += QLatin1Char(',') + QString::number((ip & 0xff0000) >> 16);
- portArg += QLatin1Char(',') + QString::number((ip & 0xff00) >> 8);
- portArg += QLatin1Char(',') + QString::number(ip & 0xff);
- portArg += QLatin1Char(',') + QString::number((port & 0xff00) >> 8);
- portArg += QLatin1Char(',') + QString::number(port & 0xff);
- currentCmd = QLatin1String("PORT ");
- currentCmd += portArg;
- } else {
-
-
- return false;
- }
- currentCmd += QLatin1String("\r\n");
- } else if (currentCmd.startsWith(QLatin1String("PASV"))) {
- if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended)
- currentCmd = QLatin1String("EPSV\r\n");
- }
- pendingCommands.pop_front();
- #if defined(QFTPPI_DEBUG)
- qDebug("QFtpPI send: %s", currentCmd.leftRef(currentCmd.length() - 2).toLatin1().constData());
- #endif
- state = Waiting;
- commandSocket.write(currentCmd.toUtf8());
- return true;
- }
- void QFtpPI::dtpConnectState(int s)
- {
- switch (s) {
- case QFtpDTP::CsClosed:
- if (waitForDtpToClose) {
-
- if (processReply())
- replyText = QLatin1String("");
- else
- return;
- }
- waitForDtpToClose = false;
- readyRead();
- return;
- case QFtpDTP::CsConnected:
- waitForDtpToConnect = false;
- startNextCmd();
- return;
- case QFtpDTP::CsHostNotFound:
- case QFtpDTP::CsConnectionRefused:
- emit error(QFtp::ConnectionRefused,
- QFtp::tr("Data Connection refused"));
- startNextCmd();
- return;
- default:
- return;
- }
- }
- class QFtpPrivate
- {
- Q_DECLARE_PUBLIC(QFtp)
- public:
- inline QFtpPrivate(QFtp *owner) : close_waitForStateChange(false), state(QFtp::Unconnected),
- transferMode(QFtp::Passive), error(QFtp::NoError), q_ptr(owner)
- { }
- ~QFtpPrivate() { while (!pending.isEmpty()) delete pending.takeFirst(); }
-
- void _q_startNextCommand();
- void _q_piFinished(const QString&);
- void _q_piError(int, const QString&);
- void _q_piConnectState(int);
- void _q_piFtpReply(int, const QString&);
- int addCommand(QFtpCommand *cmd);
- QFtpPI pi;
- QList<QFtpCommand *> pending;
- bool close_waitForStateChange;
- QFtp::State state;
- QFtp::TransferMode transferMode;
- QFtp::Error error;
- QString errorString;
- QString host;
- quint16 port;
- QString proxyHost;
- quint16 proxyPort;
- QFtp *q_ptr;
- };
- int QFtpPrivate::addCommand(QFtpCommand *cmd)
- {
- pending.append(cmd);
- if (pending.count() == 1) {
-
- QTimer::singleShot(0, q_func(), SLOT(_q_startNextCommand()));
- }
- return cmd->id;
- }
- QFtp::QFtp(QObject *parent)
- : QObject(parent), d(new QFtpPrivate(this))
- {
- d->errorString = tr("Unknown error");
- connect(&d->pi, SIGNAL(connectState(int)),
- SLOT(_q_piConnectState(int)));
- connect(&d->pi, SIGNAL(finished(QString)),
- SLOT(_q_piFinished(QString)));
- connect(&d->pi, SIGNAL(error(int,QString)),
- SLOT(_q_piError(int,QString)));
- connect(&d->pi, SIGNAL(rawFtpReply(int,QString)),
- SLOT(_q_piFtpReply(int,QString)));
- connect(&d->pi.dtp, SIGNAL(readyRead()),
- SIGNAL(readyRead()));
- connect(&d->pi.dtp, SIGNAL(dataTransferProgress(qint64,qint64)),
- SIGNAL(dataTransferProgress(qint64,qint64)));
- connect(&d->pi.dtp, SIGNAL(listInfo(QUrlInfo)),
- SIGNAL(listInfo(QUrlInfo)));
- }
- int QFtp::connectToHost(const QString &host, quint16 port)
- {
- QStringList cmds;
- cmds << host;
- cmds << QString::number((uint)port);
- int id = d->addCommand(new QFtpCommand(ConnectToHost, cmds));
- d->pi.transferConnectionExtended = true;
- return id;
- }
- int QFtp::login(const QString &user, const QString &password)
- {
- QStringList cmds;
- if (user.isNull() || user.compare(QLatin1String("anonymous"), Qt::CaseInsensitive) == 0) {
- cmds << (QLatin1String("USER ") + (user.isNull() ? QLatin1String("anonymous") : user) + QLatin1String("\r\n"));
- cmds << (QLatin1String("PASS ") + (password.isNull() ? QLatin1String("anonymous@") : password) + QLatin1String("\r\n"));
- } else {
- cmds << (QLatin1String("USER ") + user + QLatin1String("\r\n"));
- if (!password.isNull())
- cmds << (QLatin1String("PASS ") + password + QLatin1String("\r\n"));
- }
- return d->addCommand(new QFtpCommand(Login, cmds));
- }
- int QFtp::close()
- {
- return d->addCommand(new QFtpCommand(Close, QStringList(QLatin1String("QUIT\r\n"))));
- }
- int QFtp::setTransferMode(TransferMode mode)
- {
- int id = d->addCommand(new QFtpCommand(SetTransferMode, QStringList()));
- d->pi.transferConnectionExtended = true;
- d->transferMode = mode;
- return id;
- }
- int QFtp::setProxy(const QString &host, quint16 port)
- {
- QStringList args;
- args << host << QString::number(port);
- return d->addCommand(new QFtpCommand(SetProxy, args));
- }
- int QFtp::list(const QString &dir)
- {
- QStringList cmds;
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- if (dir.isEmpty())
- cmds << QLatin1String("LIST\r\n");
- else
- cmds << (QLatin1String("LIST ") + dir + QLatin1String("\r\n"));
- return d->addCommand(new QFtpCommand(List, cmds));
- }
- int QFtp::cd(const QString &dir)
- {
- return d->addCommand(new QFtpCommand(Cd, QStringList(QLatin1String("CWD ") + dir + QLatin1String("\r\n"))));
- }
- int QFtp::get(const QString &file, QIODevice *dev, TransferType type)
- {
- QStringList cmds;
- if (type == Binary)
- cmds << QLatin1String("TYPE I\r\n");
- else
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String("SIZE ") + file + QLatin1String("\r\n");
- cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- cmds << QLatin1String("RETR ") + file + QLatin1String("\r\n");
- return d->addCommand(new QFtpCommand(Get, cmds, dev));
- }
- int QFtp::put(const QByteArray &data, const QString &file, TransferType type)
- {
- QStringList cmds;
- if (type == Binary)
- cmds << QLatin1String("TYPE I\r\n");
- else
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- cmds << QLatin1String("ALLO ") + QString::number(data.size()) + QLatin1String("\r\n");
- cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n");
- return d->addCommand(new QFtpCommand(Put, cmds, data));
- }
- int QFtp::put(QIODevice *dev, const QString &file, TransferType type)
- {
- QStringList cmds;
- if (type == Binary)
- cmds << QLatin1String("TYPE I\r\n");
- else
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String(d->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- if (!dev->isSequential())
- cmds << QLatin1String("ALLO ") + QString::number(dev->size()) + QLatin1String("\r\n");
- cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n");
- return d->addCommand(new QFtpCommand(Put, cmds, dev));
- }
- int QFtp::remove(const QString &file)
- {
- return d->addCommand(new QFtpCommand(Remove, QStringList(QLatin1String("DELE ") + file + QLatin1String("\r\n"))));
- }
- int QFtp::mkdir(const QString &dir)
- {
- return d->addCommand(new QFtpCommand(Mkdir, QStringList(QLatin1String("MKD ") + dir + QLatin1String("\r\n"))));
- }
- int QFtp::rmdir(const QString &dir)
- {
- return d->addCommand(new QFtpCommand(Rmdir, QStringList(QLatin1String("RMD ") + dir + QLatin1String("\r\n"))));
- }
- int QFtp::rename(const QString &oldname, const QString &newname)
- {
- QStringList cmds;
- cmds << QLatin1String("RNFR ") + oldname + QLatin1String("\r\n");
- cmds << QLatin1String("RNTO ") + newname + QLatin1String("\r\n");
- return d->addCommand(new QFtpCommand(Rename, cmds));
- }
- int QFtp::rawCommand(const QString &command)
- {
- const QString cmd = command.trimmed() + QLatin1String("\r\n");
- return d->addCommand(new QFtpCommand(RawCommand, QStringList(cmd)));
- }
- qint64 QFtp::bytesAvailable() const
- {
- return d->pi.dtp.bytesAvailable();
- }
- qint64 QFtp::read(char *data, qint64 maxlen)
- {
- return d->pi.dtp.read(data, maxlen);
- }
- QByteArray QFtp::readAll()
- {
- return d->pi.dtp.readAll();
- }
- void QFtp::abort()
- {
- if (d->pending.isEmpty())
- return;
- clearPendingCommands();
- d->pi.abort();
- }
- void QFtp::clearError()
- {
- d->error = NoError;
- }
- int QFtp::currentId() const
- {
- if (d->pending.isEmpty())
- return 0;
- return d->pending.first()->id;
- }
- QFtp::Command QFtp::currentCommand() const
- {
- if (d->pending.isEmpty())
- return None;
- return d->pending.first()->command;
- }
- QIODevice* QFtp::currentDevice() const
- {
- if (d->pending.isEmpty())
- return nullptr;
- QFtpCommand *c = d->pending.first();
- if (c->is_ba)
- return nullptr;
- return c->data.dev;
- }
- bool QFtp::hasPendingCommands() const
- {
- return d->pending.count() > 1;
- }
- void QFtp::clearPendingCommands()
- {
-
- while (d->pending.count() > 1)
- delete d->pending.takeLast();
- }
- QFtp::State QFtp::state() const
- {
- return d->state;
- }
- QFtp::Error QFtp::error() const
- {
- return d->error;
- }
- QString QFtp::errorString() const
- {
- return d->errorString;
- }
- void QFtpPrivate::_q_startNextCommand()
- {
- Q_Q(QFtp);
- if (pending.isEmpty())
- return;
- QFtpCommand *c = pending.constFirst();
- error = QFtp::NoError;
- errorString = QT_TRANSLATE_NOOP(QFtp, QLatin1String("Unknown error"));
- if (q->bytesAvailable())
- q->readAll();
- emit q->commandStarted(c->id);
-
-
- if (c->command == QFtp::Login && !proxyHost.isEmpty()) {
- QString loginString = c->rawCmds.first().trimmed();
- loginString += QLatin1Char('@') + host;
- if (port && port != 21)
- loginString += QLatin1Char(':') + QString::number(port);
- loginString += QLatin1String("\r\n");
- c->rawCmds[0] = loginString;
- }
- if (c->command == QFtp::SetTransferMode) {
- _q_piFinished(QLatin1String("Transfer mode set"));
- } else if (c->command == QFtp::SetProxy) {
- proxyHost = c->rawCmds.at(0);
- proxyPort = c->rawCmds.at(1).toUInt();
- c->rawCmds.clear();
- _q_piFinished(QLatin1String("Proxy set to ") + proxyHost + QLatin1Char(':') + QString::number(proxyPort));
- } else if (c->command == QFtp::ConnectToHost) {
- #ifndef QT_NO_BEARERMANAGEMENT
-
- pi.setProperty("_q_networksession", q->property("_q_networksession"));
- #endif
- if (!proxyHost.isEmpty()) {
- host = c->rawCmds.at(0);
- port = c->rawCmds.at(1).toUInt();
- pi.connectToHost(proxyHost, proxyPort);
- } else {
- pi.connectToHost(c->rawCmds.at(0), c->rawCmds.at(1).toUInt());
- }
- } else {
- if (c->command == QFtp::Put) {
- if (c->is_ba) {
- pi.dtp.setData(c->data.ba);
- pi.dtp.setBytesTotal(c->data.ba->size());
- } else if (c->data.dev && (c->data.dev->isOpen() || c->data.dev->open(QIODevice::ReadOnly))) {
- pi.dtp.setDevice(c->data.dev);
- if (c->data.dev->isSequential()) {
- pi.dtp.setBytesTotal(0);
- pi.dtp.connect(c->data.dev, SIGNAL(readyRead()), SLOT(dataReadyRead()));
- pi.dtp.connect(c->data.dev, SIGNAL(readChannelFinished()), SLOT(dataReadyRead()));
- } else {
- pi.dtp.setBytesTotal(c->data.dev->size());
- }
- }
- } else if (c->command == QFtp::Get) {
- if (!c->is_ba && c->data.dev) {
- pi.dtp.setDevice(c->data.dev);
- }
- } else if (c->command == QFtp::Close) {
- state = QFtp::Closing;
- emit q->stateChanged(state);
- }
- pi.sendCommands(c->rawCmds);
- }
- }
- void QFtpPrivate::_q_piFinished(const QString&)
- {
- if (pending.isEmpty())
- return;
- QFtpCommand *c = pending.constFirst();
- if (c->command == QFtp::Close) {
-
-
-
-
- if (state != QFtp::Unconnected) {
- close_waitForStateChange = true;
- return;
- }
- }
- emit q_func()->commandFinished(c->id, false);
- pending.removeFirst();
- delete c;
- if (pending.isEmpty()) {
- emit q_func()->done(false);
- } else {
- _q_startNextCommand();
- }
- }
- void QFtpPrivate::_q_piError(int errorCode, const QString &text)
- {
- Q_Q(QFtp);
- if (pending.isEmpty()) {
- qWarning("QFtpPrivate::_q_piError was called without pending command!");
- return;
- }
- QFtpCommand *c = pending.constFirst();
-
- if (c->command == QFtp::Get && pi.currentCommand().startsWith(QLatin1String("SIZE "))) {
- pi.dtp.setBytesTotal(0);
- return;
- } else if (c->command==QFtp::Put && pi.currentCommand().startsWith(QLatin1String("ALLO "))) {
- return;
- }
- error = QFtp::Error(errorCode);
- switch (q->currentCommand()) {
- case QFtp::ConnectToHost:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Connecting to host failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Login:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Login failed:\n%1"))
- .arg(text);
- break;
- case QFtp::List:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Listing directory failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Cd:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Changing directory failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Get:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Downloading file failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Put:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Uploading file failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Remove:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing file failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Mkdir:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Creating directory failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Rmdir:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing directory failed:\n%1"))
- .arg(text);
- break;
- default:
- errorString = text;
- break;
- }
- pi.clearPendingCommands();
- q->clearPendingCommands();
- emit q->commandFinished(c->id, true);
- pending.removeFirst();
- delete c;
- if (pending.isEmpty())
- emit q->done(true);
- else
- _q_startNextCommand();
- }
- void QFtpPrivate::_q_piConnectState(int connectState)
- {
- state = QFtp::State(connectState);
- emit q_func()->stateChanged(state);
- if (close_waitForStateChange) {
- close_waitForStateChange = false;
- _q_piFinished(QLatin1String(QT_TRANSLATE_NOOP("QFtp", "Connection closed")));
- }
- }
- void QFtpPrivate::_q_piFtpReply(int code, const QString &text)
- {
- if (q_func()->currentCommand() == QFtp::RawCommand) {
- pi.rawCommand = true;
- emit q_func()->rawCommandReply(code, text);
- }
- }
- QFtp::~QFtp()
- {
- abort();
- close();
- }
- QT_END_NAMESPACE
- #include "qftp.moc"
- #include "moc_qftp.cpp"
|