1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the network module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
//#define QFTPPI_DEBUG
30
//#define QFTPDTP_DEBUG
33
#include "qabstractsocket.h"
35
#ifndef QT_NO_NETWORKPROTOCOL_FTP
37
#include "qcoreapplication.h"
38
#include "qtcpsocket.h"
40
#include "qstringlist.h"
43
#include "qfileinfo.h"
45
#include "qtcpserver.h"
50
The QFtpDTP (DTP = Data Transfer Process) controls all client side
51
data transfer between the client and server.
53
class QFtpDTP : public QObject
66
QFtpDTP(QFtpPI *p, QObject *parent = 0);
68
void setData(QByteArray *);
69
void setDevice(QIODevice *);
71
void setBytesTotal(qint64 bytes);
73
bool hasError() const;
74
QString errorMessage() const;
77
void connectToHost(const QString & host, quint16 port);
78
int setupListener(const QHostAddress &address);
80
QTcpSocket::SocketState state() const;
81
qint64 bytesAvailable() const;
82
qint64 read(char *data, qint64 maxlen);
85
void abortConnection();
87
static bool parseDir(const QString &buffer, const QString &userName, QUrlInfo *info);
90
void listInfo(const QUrlInfo&);
92
void dataTransferProgress(qint64, qint64);
94
void connectState(int);
97
void socketConnected();
98
void socketReadyRead();
99
void socketError(QTcpSocket::SocketError);
100
void socketConnectionClosed();
101
void socketBytesWritten(qint64);
116
// If is_ba is true, ba is used; ba is never 0.
117
// Otherwise dev is used; dev can be 0 or not.
124
QByteArray bytesFromSocket;
127
/**********************************************************************
129
* QFtpPI - Protocol Interpreter
131
*********************************************************************/
133
class QFtpPI : public QObject
138
QFtpPI(QObject *parent = 0);
140
void connectToHost(const QString &host, quint16 port);
142
bool sendCommands(const QStringList &cmds);
143
bool sendCommand(const QString &cmd)
144
{ return sendCommands(QStringList(cmd)); }
146
void clearPendingCommands();
149
QString currentCommand() const
150
{ return currentCmd; }
153
bool transferConnectionExtended;
155
QFtpDTP dtp; // the PI has a DTP which is not the design of RFC 959, but it
156
// makes the design simpler this way
158
void connectState(int);
159
void finished(const QString&);
160
void error(int, const QString&);
161
void rawFtpReply(int, const QString&);
166
void connectionClosed();
167
void delayedCloseFinished();
169
void error(QTcpSocket::SocketError);
171
void dtpConnectState(int);
174
// the states are modelled after the generalized state diagram of RFC 959,
193
QTcpSocket commandSocket;
197
AbortState abortState;
198
QStringList pendingCommands;
201
bool waitForDtpToConnect;
202
bool waitForDtpToClose;
204
QByteArray bytesFromSocket;
206
friend class QFtpDTP;
209
/**********************************************************************
211
* QFtpCommand implemenatation
213
*********************************************************************/
217
QFtpCommand(QFtp::Command cmd, QStringList raw, const QByteArray &ba);
218
QFtpCommand(QFtp::Command cmd, QStringList raw, QIODevice *dev = 0);
222
QFtp::Command command;
225
// If is_ba is true, ba is used; ba is never 0.
226
// Otherwise dev is used; dev can be 0 or not.
233
static QBasicAtomic idCounter;
237
QBasicAtomic QFtpCommand::idCounter = Q_ATOMIC_INIT(1);
238
int QFtpCommand::nextId()
243
if (idCounter.testAndSet(id, id + 1))
249
QFtpCommand::QFtpCommand(QFtp::Command cmd, QStringList raw, const QByteArray &ba)
250
: command(cmd), rawCmds(raw), is_ba(true)
253
data.ba = new QByteArray(ba);
256
QFtpCommand::QFtpCommand(QFtp::Command cmd, QStringList raw, QIODevice *dev)
257
: command(cmd), rawCmds(raw), is_ba(false)
263
QFtpCommand::~QFtpCommand()
269
/**********************************************************************
271
* QFtpDTP implemenatation
273
*********************************************************************/
274
QFtpDTP::QFtpDTP(QFtpPI *p, QObject *parent) :
282
listener.setObjectName("QFtpDTP active state server");
283
connect(&listener, SIGNAL(newConnection()), SLOT(setupSocket()));
286
void QFtpDTP::setData(QByteArray *ba)
292
void QFtpDTP::setDevice(QIODevice *dev)
298
void QFtpDTP::setBytesTotal(qint64 bytes)
302
emit dataTransferProgress(bytesDone, bytesTotal);
305
void QFtpDTP::connectToHost(const QString & host, quint16 port)
307
bytesFromSocket.clear();
311
socket = new QTcpSocket(this);
312
socket->setObjectName("QFtpDTP Passive state socket");
313
connect(socket, SIGNAL(connected()), SLOT(socketConnected()));
314
connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
315
connect(socket, SIGNAL(error(SocketError)), SLOT(socketError(SocketError)));
316
connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed()));
317
connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
319
socket->connectToHost(host, port);
322
int QFtpDTP::setupListener(const QHostAddress &address)
324
if (!listener.listen(address, 0))
327
return listener.serverPort();
330
QTcpSocket::SocketState QFtpDTP::state() const
332
return socket ? socket->state() : QTcpSocket::UnconnectedState;
335
qint64 QFtpDTP::bytesAvailable() const
337
if (!socket || socket->state() != QTcpSocket::ConnectedState)
338
return (qint64) bytesFromSocket.size();
339
return socket->bytesAvailable();
342
qint64 QFtpDTP::read(char *data, qint64 maxlen)
345
if (socket && socket->state() == QTcpSocket::ConnectedState) {
346
read = socket->read(data, maxlen);
348
read = bytesFromSocket.size();
349
memcpy(data, bytesFromSocket.data(), read);
350
bytesFromSocket.clear();
357
QByteArray QFtpDTP::readAll()
360
if (socket && socket->state() == QTcpSocket::ConnectedState) {
361
tmp = socket->readAll();
362
bytesDone += tmp.size();
364
tmp = bytesFromSocket;
365
bytesFromSocket.clear();
370
void QFtpDTP::writeData()
376
#if defined(QFTPDTP_DEBUG)
377
qDebug("QFtpDTP::writeData: write %d bytes", data.ba->size());
379
if (data.ba->size() == 0)
380
emit dataTransferProgress(0, bytesTotal);
382
socket->write(data.ba->data(), data.ba->size());
387
} else if (data.dev) {
388
callWriteData = false;
389
const qint64 blockSize = 16*1024;
391
while (!data.dev->atEnd() && socket->bytesToWrite() == 0) {
392
qint64 read = data.dev->read(buf, blockSize);
393
#if defined(QFTPDTP_DEBUG)
394
qDebug("QFtpDTP::writeData: write() of size %lli bytes", read);
396
socket->write(buf, read);
398
return; // this can happen when a command is aborted
400
if (data.dev->atEnd()) {
401
if (bytesDone == 0 && socket->bytesToWrite() == 0)
402
emit dataTransferProgress(0, bytesTotal);
406
callWriteData = true;
411
inline bool QFtpDTP::hasError() const
413
return !err.isNull();
416
inline QString QFtpDTP::errorMessage() const
421
inline void QFtpDTP::clearError()
426
void QFtpDTP::abortConnection()
428
#if defined(QFTPDTP_DEBUG)
429
qDebug("QFtpDTP::abortConnection, bytesAvailable == %lli",
430
socket ? socket->bytesAvailable() : (qint64) 0);
432
callWriteData = false;
439
bool QFtpDTP::parseDir(const QString &buffer, const QString &userName, QUrlInfo *info)
441
QStringList lst = buffer.simplified().split(" ");
451
if (tmp[0] == QChar('d')) {
453
info->setFile(false);
454
info->setSymLink(false);
455
} else if (tmp[0] == QChar('-')) {
458
info->setSymLink(false);
459
} else if (tmp[0] == QChar('l')) {
461
info->setFile(false);
462
info->setSymLink(true);
468
static int group = 1;
469
static int other = 2;
470
static int readable = 0;
471
static int writable = 1;
472
static int executable = 2;
475
perms[0][0] = (tmp[1] == 'r');
476
perms[0][1] = (tmp[2] == 'w');
477
perms[0][2] = (tmp[3] == 'x');
478
perms[1][0] = (tmp[4] == 'r');
479
perms[1][1] = (tmp[5] == 'w');
480
perms[1][2] = (tmp[6] == 'x');
481
perms[2][0] = (tmp[7] == 'r');
482
perms[2][1] = (tmp[8] == 'w');
483
perms[2][2] = (tmp[9] == 'x');
493
// detect permissions
494
info->setWritable((userName == info->owner() && perms[user][writable]) ||
495
perms[other][writable]);
496
info->setReadable((userName == info->owner() && perms[user][readable]) ||
497
perms[other][readable]);
500
if (perms[user][readable])
501
p |= QUrlInfo::ReadOwner;
502
if (perms[user][writable])
503
p |= QUrlInfo::WriteOwner;
504
if (perms[user][executable])
505
p |= QUrlInfo::ExeOwner;
506
if (perms[group][readable])
507
p |= QUrlInfo::ReadGroup;
508
if (perms[group][writable])
509
p |= QUrlInfo::WriteGroup;
510
if (perms[group][executable])
511
p |= QUrlInfo::ExeGroup;
512
if (perms[other][readable])
513
p |= QUrlInfo::ReadOther;
514
if (perms[other][writable])
515
p |= QUrlInfo::WriteOther;
516
if (perms[other][executable])
517
p |= QUrlInfo::ExeOther;
518
info->setPermissions(p);
522
info->setSize(tmp.toInt());
528
lst[5] = lst[5].toUpper();
530
dateStr += QLatin1Char(' ');
532
dateStr += QLatin1Char(' ');
534
if (lst[7].contains(":")) {
535
time = QTime(lst[7].left(2).toInt(), lst[7].right(2).toInt());
536
dateStr += QString::number(QDate::currentDate().year());
541
QDate date = QDate::fromString(dateStr);
542
info->setLastModified(QDateTime(date, time));
544
if (lst[7].contains(":")) {
545
// if the year-field is missing, check the modification date/time of
546
// the file and compare to "now". If the file was changed in the
547
// "future", also considering a possible 13 hour time zone gap, then
548
// we assume it was changed a year ago.
549
const int futureTolerance = 46800;
550
if(info->lastModified().secsTo(QDateTime::currentDateTime()) < -futureTolerance) {
551
QDateTime dt = info->lastModified();
553
d.setYMD(d.year()-1, d.month(), d.day());
555
info->setLastModified(dt);
560
if (info->isSymLink())
561
info->setName(lst[8].trimmed());
564
for (int i = 8; i < lst.count(); ++i)
572
void QFtpDTP::socketConnected()
575
#if defined(QFTPDTP_DEBUG)
576
qDebug("QFtpDTP::connectState(CsConnected)");
578
emit connectState(QFtpDTP::CsConnected);
581
void QFtpDTP::socketReadyRead()
586
if (pi->currentCommand().isEmpty()) {
588
#if defined(QFTPDTP_DEBUG)
589
qDebug("QFtpDTP::connectState(CsClosed)");
591
emit connectState(QFtpDTP::CsClosed);
595
if (pi->abortState == QFtpPI::AbortStarted) {
601
if (pi->currentCommand().startsWith("LIST")) {
602
while (socket->canReadLine()) {
604
QString line = socket->readLine();
605
#if defined(QFTPDTP_DEBUG)
606
qDebug("QFtpDTP read (list): '%s'", line.toLatin1().constData());
608
if (parseDir(line, "", &i)) {
611
// some FTP servers don't return a 550 if the file or directory
612
// does not exist, but rather write a text to the data socket
613
// -- try to catch these cases
614
if (line.endsWith("No such file or directory\r\n"))
619
if (!is_ba && data.dev) {
621
ba.resize(socket->bytesAvailable());
622
qint64 bytesRead = socket->read(ba.data(), ba.size());
624
// a read following a readyRead() signal will
628
ba.resize(bytesRead);
629
bytesDone += bytesRead;
630
#if defined(QFTPDTP_DEBUG)
631
qDebug("QFtpDTP read: %lli bytes (total %lli bytes)", bytesRead, bytesDone);
633
emit dataTransferProgress(bytesDone, bytesTotal);
636
#if defined(QFTPDTP_DEBUG)
637
qDebug("QFtpDTP readyRead: %lli bytes available (total %lli bytes read)",
638
bytesAvailable(), bytesDone);
640
emit dataTransferProgress(bytesDone+socket->bytesAvailable(), bytesTotal);
646
void QFtpDTP::socketError(QTcpSocket::SocketError e)
648
if (e == QTcpSocket::HostNotFoundError) {
649
#if defined(QFTPDTP_DEBUG)
650
qDebug("QFtpDTP::connectState(CsHostNotFound)");
652
emit connectState(QFtpDTP::CsHostNotFound);
653
} else if (e == QTcpSocket::ConnectionRefusedError) {
654
#if defined(QFTPDTP_DEBUG)
655
qDebug("QFtpDTP::connectState(CsConnectionRefused)");
657
emit connectState(QFtpDTP::CsConnectionRefused);
661
void QFtpDTP::socketConnectionClosed()
663
if (!is_ba && data.dev) {
667
bytesFromSocket = socket->readAll();
668
#if defined(QFTPDTP_DEBUG)
669
qDebug("QFtpDTP::connectState(CsClosed)");
671
emit connectState(QFtpDTP::CsClosed);
674
void QFtpDTP::socketBytesWritten(qint64 bytes)
677
#if defined(QFTPDTP_DEBUG)
678
qDebug("QFtpDTP::bytesWritten(%lli)", bytesDone);
680
emit dataTransferProgress(bytesDone, bytesTotal);
685
void QFtpDTP::setupSocket()
687
socket = listener.nextPendingConnection();
688
socket->setObjectName("QFtpDTP Active state socket");
689
connect(socket, SIGNAL(connected()), SLOT(socketConnected()));
690
connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
691
connect(socket, SIGNAL(error(SocketError)), SLOT(socketError(SocketError)));
692
connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed()));
693
connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
698
void QFtpDTP::clearData()
704
/**********************************************************************
706
* QFtpPI implemenatation
708
*********************************************************************/
709
QFtpPI::QFtpPI(QObject *parent) :
712
transferConnectionExtended(true),
715
state(Begin), abortState(None),
716
currentCmd(QString()),
717
waitForDtpToConnect(false),
718
waitForDtpToClose(false)
720
commandSocket.setObjectName("QFtpPI_socket");
721
connect(&commandSocket, SIGNAL(hostFound()),
723
connect(&commandSocket, SIGNAL(connected()),
725
connect(&commandSocket, SIGNAL(disconnected()),
726
SLOT(connectionClosed()));
727
connect(&commandSocket, SIGNAL(readyRead()),
729
connect(&commandSocket, SIGNAL(error(SocketError)),
730
SLOT(error(SocketError)));
732
connect(&dtp, SIGNAL(connectState(int)),
733
SLOT(dtpConnectState(int)));
736
void QFtpPI::connectToHost(const QString &host, quint16 port)
738
emit connectState(QFtp::HostLookup);
739
commandSocket.connectToHost(host, port);
743
Sends the sequence of commands \a cmds to the FTP server. When the commands
744
are all done the finished() signal is emitted. When an error occurs, the
745
error() signal is emitted.
747
If there are pending commands in the queue this functions returns false and
748
the \a cmds are not added to the queue; otherwise it returns true.
750
bool QFtpPI::sendCommands(const QStringList &cmds)
752
if (!pendingCommands.isEmpty())
755
if (commandSocket.state() != QTcpSocket::ConnectedState || state!=Idle) {
756
emit error(QFtp::NotConnected, QFtp::tr("Not connected"));
757
return true; // there are no pending commands
760
pendingCommands = cmds;
765
void QFtpPI::clearPendingCommands()
767
pendingCommands.clear();
768
dtp.abortConnection();
775
pendingCommands.clear();
777
if (abortState != None)
781
abortState = AbortStarted;
782
#if defined(QFTPPI_DEBUG)
783
qDebug("QFtpPI send: ABOR");
785
commandSocket.write("ABOR\r\n", 6);
787
if (currentCmd.startsWith("STOR "))
788
dtp.abortConnection();
791
void QFtpPI::hostFound()
793
emit connectState(QFtp::Connecting);
796
void QFtpPI::connected()
799
#if defined(QFTPPI_DEBUG)
800
// qDebug("QFtpPI state: %d [connected()]", state);
802
emit connectState(QFtp::Connected);
805
void QFtpPI::connectionClosed()
807
commandSocket.close();
808
emit connectState(QFtp::Unconnected);
811
void QFtpPI::delayedCloseFinished()
813
emit connectState(QFtp::Unconnected);
816
void QFtpPI::error(QTcpSocket::SocketError e)
818
if (e == QTcpSocket::HostNotFoundError) {
819
emit connectState(QFtp::Unconnected);
820
emit error(QFtp::HostNotFound,
821
QFtp::tr("Host %1 not found").arg(commandSocket.peerName()));
822
} else if (e == QTcpSocket::ConnectionRefusedError) {
823
emit connectState(QFtp::Unconnected);
824
emit error(QFtp::ConnectionRefused,
825
QFtp::tr("Connection refused to host %1").arg(commandSocket.peerName()));
829
void QFtpPI::readyRead()
831
if (waitForDtpToClose)
834
while (commandSocket.canReadLine()) {
835
// read line with respect to line continuation
836
QString line = commandSocket.readLine();
837
if (replyText.isEmpty()) {
838
if (line.length() < 3) {
842
const int lowerLimit[3] = {1,0,0};
843
const int upperLimit[3] = {5,5,9};
844
for (int i=0; i<3; i++) {
845
replyCode[i] = line[i].digitValue();
846
if (replyCode[i]<lowerLimit[i] || replyCode[i]>upperLimit[i]) {
852
QString endOfMultiLine;
853
endOfMultiLine[0] = '0' + replyCode[0];
854
endOfMultiLine[1] = '0' + replyCode[1];
855
endOfMultiLine[2] = '0' + replyCode[2];
856
endOfMultiLine[3] = ' ';
857
QString lineCont(endOfMultiLine);
859
QString lineLeft4 = line.left(4);
861
while (lineLeft4 != endOfMultiLine) {
862
if (lineLeft4 == lineCont)
863
replyText += line.mid(4); // strip 'xyz-'
866
if (!commandSocket.canReadLine())
868
line = commandSocket.readLine();
869
lineLeft4 = line.left(4);
871
replyText += line.mid(4); // strip reply code 'xyz '
872
if (replyText.endsWith("\r\n"))
881
Process a reply from the FTP server.
883
Returns true if the reply was processed or false if the reply has to be
884
processed at a later point.
886
bool QFtpPI::processReply()
888
#if defined(QFTPPI_DEBUG)
889
// qDebug("QFtpPI state: %d [processReply() begin]", state);
890
if (replyText.length() < 400)
891
qDebug("QFtpPI recv: %d %s", 100*replyCode[0]+10*replyCode[1]+replyCode[2], replyText.toLatin1().constData());
893
qDebug("QFtpPI recv: %d (text skipped)", 100*replyCode[0]+10*replyCode[1]+replyCode[2]);
896
// process 226 replies ("Closing Data Connection") only when the data
897
// connection is really closed to avoid short reads of the DTP
898
if (100*replyCode[0]+10*replyCode[1]+replyCode[2] == 226) {
899
if (dtp.state() != QTcpSocket::UnconnectedState) {
900
waitForDtpToClose = true;
905
switch (abortState) {
907
abortState = WaitForAbortToFinish;
909
case WaitForAbortToFinish:
917
static const State table[5] = {
918
/* 1yz 2yz 3yz 4yz 5yz */
919
Waiting, Success, Idle, Failure, Failure
923
if (replyCode[0] == 1) {
925
} else if (replyCode[0] == 2) {
927
emit finished(QFtp::tr("Connected to host %1").arg(commandSocket.peerName()));
930
// reply codes not starting with 1 or 2 are not handled.
933
if (static_cast<signed char>(replyCode[0]) < 0 || replyCode[0] > 5)
936
#if defined(Q_OS_IRIX) && defined(Q_CC_GNU)
938
// work around a crash on 64 bit gcc IRIX
939
State *t = (State *) table;
940
state = t[replyCode[0] - 1];
943
state = table[replyCode[0] - 1];
947
// ignore unrequested message
950
#if defined(QFTPPI_DEBUG)
951
// qDebug("QFtpPI state: %d [processReply() intermediate]", state);
954
// special actions on certain replies
955
int replyCodeInt = 100*replyCode[0] + 10*replyCode[1] + replyCode[2];
956
emit rawFtpReply(replyCodeInt, replyText);
959
} else if (replyCodeInt == 227) {
960
// 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
961
// rfc959 does not define this response precisely, and gives
962
// both examples where the parenthesis are used, and where
963
// they are missing. We need to scan for the address and host
965
QRegExp addrPortPattern("(\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)");
966
if (addrPortPattern.indexIn(replyText) == -1) {
967
#if defined(QFTPPI_DEBUG)
968
qDebug("QFtp: bad 227 response -- address and port information missing");
970
// this error should be reported
972
QStringList lst = addrPortPattern.capturedTexts();
973
QString host = lst[1] + "." + lst[2] + "." + lst[3] + "." + lst[4];
974
quint16 port = (lst[5].toUInt() << 8) + lst[6].toUInt();
975
waitForDtpToConnect = true;
976
dtp.connectToHost(host, port);
978
} else if (replyCodeInt == 229) {
979
// 229 Extended Passive mode OK (|||10982|)
980
int portPos = replyText.indexOf('(');
982
#if defined(QFTPPI_DEBUG)
983
qDebug("QFtp: bad 229 response -- port information missing");
985
// this error should be reported
988
QChar delimiter = replyText.at(portPos);
989
QStringList epsvParameters = replyText.mid(portPos).split(delimiter);
991
waitForDtpToConnect = true;
992
dtp.connectToHost(commandSocket.peerAddress().toString(),
993
epsvParameters.at(3).toInt());
996
} else if (replyCodeInt == 230) {
997
if (currentCmd.startsWith("USER ") && pendingCommands.count()>0 &&
998
pendingCommands.first().startsWith("PASS ")) {
999
// no need to send the PASS -- we are already logged in
1000
pendingCommands.pop_front();
1002
// 230 User logged in, proceed.
1003
emit connectState(QFtp::LoggedIn);
1004
} else if (replyCodeInt == 213) {
1006
if (currentCmd.startsWith("SIZE "))
1007
dtp.setBytesTotal(replyText.simplified().toInt());
1008
} else if (replyCode[0]==1 && currentCmd.startsWith("STOR ")) {
1012
// react on new state
1015
// should never happen
1022
if (dtp.hasError()) {
1023
emit error(QFtp::UnknownError, dtp.errorMessage());
1032
// If the EPSV or EPRT commands fail, replace them with
1033
// the old PASV and PORT instead and try again.
1034
if (currentCmd.startsWith("EPSV")) {
1035
transferConnectionExtended = false;
1036
pendingCommands.prepend("PASV\r\n");
1037
} else if (currentCmd.startsWith("EPRT")) {
1038
transferConnectionExtended = false;
1039
pendingCommands.prepend("PORT\r\n");
1041
emit error(QFtp::UnknownError, replyText);
1047
#if defined(QFTPPI_DEBUG)
1048
// qDebug("QFtpPI state: %d [processReply() end]", state);
1054
Starts next pending command. Returns false if there are no pending commands,
1055
otherwise it returns true.
1057
bool QFtpPI::startNextCmd()
1059
if (waitForDtpToConnect)
1060
// don't process any new commands until we are connected
1063
#if defined(QFTPPI_DEBUG)
1065
qDebug("QFtpPI startNextCmd: Internal error! QFtpPI called in non-Idle state %d", state);
1067
if (pendingCommands.isEmpty()) {
1069
emit finished(replyText);
1072
currentCmd = pendingCommands.first();
1074
// PORT and PASV are edited in-place, depending on whether we
1075
// should try the extended transfer connection commands EPRT and
1076
// EPSV. The PORT command also triggers setting up a listener, and
1077
// the address/port arguments are edited in.
1078
if (currentCmd.startsWith("PORT")) {
1079
QHostAddress address = commandSocket.localAddress();
1081
if (transferConnectionExtended) {
1082
int port = dtp.setupListener(address);
1083
currentCmd = "EPRT |";
1084
currentCmd += (address.protocol() == QTcpSocket::IPv4Protocol) ? "1" : "2";
1085
currentCmd += "|" + address.toString() + "|" + QString::number(port);
1087
} else if (address.protocol() == QTcpSocket::IPv4Protocol) {
1088
int port = dtp.setupListener(address);
1090
quint32 ip = address.toIPv4Address();
1091
portArg += QString::number((ip & 0xff000000) >> 24);
1092
portArg += "," + QString::number((ip & 0xff0000) >> 16);
1093
portArg += "," + QString::number((ip & 0xff00) >> 8);
1094
portArg += "," + QString::number(ip & 0xff);
1095
portArg += "," + QString::number((port & 0xff00) >> 8);
1096
portArg += "," + QString::number(port & 0xff);
1098
currentCmd = "PORT ";
1099
currentCmd += portArg;
1101
// No IPv6 connection can be set up with the PORT
1106
currentCmd += "\r\n";
1107
} else if (currentCmd.startsWith("PASV")) {
1108
if (transferConnectionExtended)
1109
currentCmd = "EPSV\r\n";
1112
pendingCommands.pop_front();
1113
#if defined(QFTPPI_DEBUG)
1114
qDebug("QFtpPI send: %s", currentCmd.left(currentCmd.length()-2).toLatin1().constData());
1117
commandSocket.write(currentCmd.toLatin1());
1121
void QFtpPI::dtpConnectState(int s)
1124
case QFtpDTP::CsClosed:
1125
if (waitForDtpToClose) {
1126
// there is an unprocessed reply
1132
waitForDtpToClose = false;
1135
case QFtpDTP::CsConnected:
1136
waitForDtpToConnect = false;
1139
case QFtpDTP::CsHostNotFound:
1140
case QFtpDTP::CsConnectionRefused:
1141
emit error(QFtp::ConnectionRefused,
1142
QFtp::tr("Connection refused for data connection"));
1150
/**********************************************************************
1154
*********************************************************************/
1156
#include <private/qobject_p.h>
1158
class QFtpPrivate : public QObjectPrivate
1160
Q_DECLARE_PUBLIC(QFtp)
1163
inline QFtpPrivate() : close_waitForStateChange(false), state(QFtp::Unconnected),
1164
transferMode(QFtp::Passive), error(QFtp::NoError)
1167
~QFtpPrivate() { while (!pending.isEmpty()) delete pending.takeFirst(); }
1170
void startNextCommand();
1171
void piFinished(const QString&);
1172
void piError(int, const QString&);
1173
void piConnectState(int);
1174
void piFtpReply(int, const QString&);
1176
int addCommand(QFtpCommand *cmd);
1179
QList<QFtpCommand *> pending;
1180
bool close_waitForStateChange;
1182
QFtp::TransferMode transferMode;
1184
QString errorString;
1192
int QFtpPrivate::addCommand(QFtpCommand *cmd)
1194
pending.append(cmd);
1196
if (pending.count() == 1) {
1197
// don't emit the commandStarted() signal before the ID is returned
1198
QTimer::singleShot(0, q_func(), SLOT(startNextCommand()));
1203
/**********************************************************************
1205
* QFtp implementation
1207
*********************************************************************/
1210
\brief The QFtp class provides an implementation of the FTP protocol.
1216
This class provides a client for the FTP protocol.
1218
The class works asynchronously, so there are no blocking
1219
functions. If an operation cannot be executed immediately, the
1220
function will still return straight away and the operation will be
1221
scheduled for later execution. The results of scheduled operations
1222
are reported via signals. This approach depends on the event loop
1225
The operations that can be scheduled (they are called "commands"
1226
in the rest of the documentation) are the following:
1227
connectToHost(), login(), close(), list(), cd(), get(), put(),
1228
remove(), mkdir(), rmdir(), rename() and rawCommand().
1230
All of these commands return a unique identifier that allows you
1231
to keep track of the command that is currently being executed.
1232
When the execution of a command starts, the commandStarted()
1233
signal with the command's identifier is emitted. When the command
1234
is finished, the commandFinished() signal is emitted with the
1235
command's identifier and a bool that indicates whether the command
1236
finished with an error.
1238
In some cases, you might want to execute a sequence of commands,
1239
e.g. if you want to connect and login to a FTP server. This is
1243
QFtp *ftp = new QFtp(this); // this is an optional QObject parent
1244
ftp->connectToHost("ftp.trolltech.com");
1248
In this case two FTP commands have been scheduled. When the last
1249
scheduled command has finished, a done() signal is emitted with
1250
a bool argument that tells you whether the sequence finished with
1253
If an error occurs during the execution of one of the commands in
1254
a sequence of commands, all the pending commands (i.e. scheduled,
1255
but not yet executed commands) are cleared and no signals are
1258
Some commands, e.g. list(), emit additional signals to report
1261
Example: If you want to download the INSTALL file from Trolltech's
1262
FTP server, you would write this:
1265
ftp->connectToHost("ftp.trolltech.com"); // id == 1
1266
ftp->login(); // id == 2
1267
ftp->cd("qt"); // id == 3
1268
ftp->get("INSTALL"); // id == 4
1269
ftp->close(); // id == 5
1272
For this example the following sequence of signals is emitted
1273
(with small variations, depending on network traffic, etc.):
1277
stateChanged(HostLookup)
1278
stateChanged(Connecting)
1279
stateChanged(Connected)
1283
stateChanged(LoggedIn)
1290
dataTransferProgress(0, 3798)
1291
dataTransferProgress(2896, 3798)
1293
dataTransferProgress(3798, 3798)
1298
stateChanged(Closing)
1299
stateChanged(Unconnected)
1305
The dataTransferProgress() signal in the above example is useful
1306
if you want to show a \link QProgressBar progressbar \endlink to
1307
inform the user about the progress of the download. The
1308
readyRead() signal tells you that there is data ready to be read.
1309
The amount of data can be queried then with the bytesAvailable()
1310
function and it can be read with the read() or readAll()
1313
If the login fails for the above example, the signals would look
1318
stateChanged(HostLookup)
1319
stateChanged(Connecting)
1320
stateChanged(Connected)
1329
You can then get details about the error with the error() and
1330
errorString() functions.
1332
For file transfer, QFtp can use both active or passive mode, and
1333
it uses passive file transfer mode by default; see the
1334
documentation for setTransferMode() for more details about this.
1336
Call setProxy() to make QFtp connect via an FTP proxy server.
1338
The functions currentId() and currentCommand() provide more
1339
information about the currently executing command.
1341
The functions hasPendingCommands() and clearPendingCommands()
1342
allow you to query and clear the list of pending commands.
1344
If you are an experienced network programmer and want to have
1345
complete control you can use rawCommand() to execute arbitrary FTP
1348
The \l{network/ftp}{FTP} example illustrates how to write FTP clients
1351
\sa {Network Module}, QHttp
1356
Constructs a QFtp object with the given \a parent.
1358
QFtp::QFtp(QObject *parent)
1359
: QObject(*new QFtpPrivate, parent)
1362
d->errorString = tr("Unknown error");
1364
connect(&d->pi, SIGNAL(connectState(int)),
1365
SLOT(piConnectState(int)));
1366
connect(&d->pi, SIGNAL(finished(QString)),
1367
SLOT(piFinished(QString)));
1368
connect(&d->pi, SIGNAL(error(int,QString)),
1369
SLOT(piError(int,QString)));
1370
connect(&d->pi, SIGNAL(rawFtpReply(int,QString)),
1371
SLOT(piFtpReply(int,QString)));
1373
connect(&d->pi.dtp, SIGNAL(readyRead()),
1374
SIGNAL(readyRead()));
1375
connect(&d->pi.dtp, SIGNAL(dataTransferProgress(qint64,qint64)),
1376
SIGNAL(dataTransferProgress(qint64,qint64)));
1377
connect(&d->pi.dtp, SIGNAL(listInfo(QUrlInfo)),
1378
SIGNAL(listInfo(QUrlInfo)));
1383
Use one of the constructors that doesn't take the \a name
1384
argument and then use setObjectName() instead.
1386
QFtp::QFtp(QObject *parent, const char *name)
1387
: QObject(*new QFtpPrivate, parent)
1390
setObjectName(name);
1391
d->errorString = tr("Unknown error");
1393
connect(&d->pi, SIGNAL(connectState(int)),
1394
SLOT(piConnectState(int)));
1395
connect(&d->pi, SIGNAL(finished(QString)),
1396
SLOT(piFinished(QString)));
1397
connect(&d->pi, SIGNAL(error(int,QString)),
1398
SLOT(piError(int,QString)));
1399
connect(&d->pi, SIGNAL(rawFtpReply(int,QString)),
1400
SLOT(piFtpReply(int,QString)));
1402
connect(&d->pi.dtp, SIGNAL(readyRead()),
1403
SIGNAL(readyRead()));
1404
connect(&d->pi.dtp, SIGNAL(dataTransferProgress(qint64,qint64)),
1405
SIGNAL(dataTransferProgress(qint64,qint64)));
1406
connect(&d->pi.dtp, SIGNAL(listInfo(QUrlInfo)),
1407
SIGNAL(listInfo(QUrlInfo)));
1414
This enum defines the connection state:
1416
\value Unconnected There is no connection to the host.
1417
\value HostLookup A host name lookup is in progress.
1418
\value Connecting An attempt to connect to the host is in progress.
1419
\value Connected Connection to the host has been achieved.
1420
\value LoggedIn Connection and user login have been achieved.
1421
\value Closing The connection is closing down, but it is not yet
1422
closed. (The state will be \c Unconnected when the connection is
1425
\sa stateChanged() state()
1428
\enum QFtp::TransferMode
1430
FTP works with two socket connections; one for commands and
1431
another for transmitting data. While the command connection is
1432
always initiated by the client, the second connection can be
1433
initiated by either the client or the server.
1435
This enum defines whether the client (Passive mode) or the server
1436
(Active mode) should set up the data connection.
1438
\value Passive The client connects to the server to transmit its
1441
\value Active The server connects to the client to transmit its
1445
\enum QFtp::TransferType
1447
This enum identifies the data transfer type used with get and
1450
\value Binary The data will be transferred in Binary mode.
1452
\value Ascii The data will be transferred in Ascii mode and new line
1453
characters will be converted to the local format.
1458
This enum identifies the error that occurred.
1460
\value NoError No error occurred.
1461
\value HostNotFound The host name lookup failed.
1462
\value ConnectionRefused The server refused the connection.
1463
\value NotConnected Tried to send a command, but there is no connection to
1465
\value UnknownError An error other than those specified above
1474
This enum is used as the return value for the currentCommand() function.
1475
This allows you to perform specific actions for particular
1476
commands, e.g. in a FTP client, you might want to clear the
1477
directory view when a list() command is started; in this case you
1478
can simply check in the slot connected to the start() signal if
1479
the currentCommand() is \c List.
1481
\value None No command is being executed.
1482
\value SetTransferMode set the \link TransferMode transfer\endlink mode.
1483
\value SetProxy switch proxying on or off.
1484
\value ConnectToHost connectToHost() is being executed.
1485
\value Login login() is being executed.
1486
\value Close close() is being executed.
1487
\value List list() is being executed.
1488
\value Cd cd() is being executed.
1489
\value Get get() is being executed.
1490
\value Put put() is being executed.
1491
\value Remove remove() is being executed.
1492
\value Mkdir mkdir() is being executed.
1493
\value Rmdir rmdir() is being executed.
1494
\value Rename rename() is being executed.
1495
\value RawCommand rawCommand() is being executed.
1497
\sa currentCommand()
1501
\fn void QFtp::stateChanged(int state)
1503
This signal is emitted when the state of the connection changes.
1504
The argument \a state is the new state of the connection; it is
1505
one of the \l State values.
1507
It is usually emitted in response to a connectToHost() or close()
1508
command, but it can also be emitted "spontaneously", e.g. when the
1509
server closes the connection unexpectedly.
1511
\sa connectToHost() close() state() State
1515
\fn void QFtp::listInfo(const QUrlInfo &i);
1517
This signal is emitted for each directory entry the list() command
1518
finds. The details of the entry are stored in \a i.
1524
\fn void QFtp::commandStarted(int id)
1526
This signal is emitted when processing the command identified by
1529
\sa commandFinished() done()
1533
\fn void QFtp::commandFinished(int id, bool error)
1535
This signal is emitted when processing the command identified by
1536
\a id has finished. \a error is true if an error occurred during
1537
the processing; otherwise \a error is false.
1539
\sa commandStarted() done() error() errorString()
1543
\fn void QFtp::done(bool error)
1545
This signal is emitted when the last pending command has finished;
1546
(it is emitted after the last command's commandFinished() signal).
1547
\a error is true if an error occurred during the processing;
1548
otherwise \a error is false.
1550
\sa commandFinished() error() errorString()
1554
\fn void QFtp::readyRead()
1556
This signal is emitted in response to a get() command when there
1557
is new data to read.
1559
If you specify a device as the second argument in the get()
1560
command, this signal is \e not emitted; instead the data is
1561
written directly to the device.
1563
You can read the data with the readAll() or read() functions.
1565
This signal is useful if you want to process the data in chunks as
1566
soon as it becomes available. If you are only interested in the
1567
complete data, just connect to the commandFinished() signal and
1568
read the data then instead.
1570
\sa get() read() readAll() bytesAvailable()
1574
\fn void QFtp::dataTransferProgress(qint64 done, qint64 total)
1576
This signal is emitted in response to a get() or put() request to
1577
indicate the current progress of the download or upload.
1579
\a done is the amount of data that has already been transferred
1580
and \a total is the total amount of data to be read or written. It
1581
is possible that the QFtp class is not able to determine the total
1582
amount of data that should be transferred, in which case \a total
1583
is 0. (If you connect this signal to a QProgressBar, the progress
1584
bar shows a busy indicator if the total is 0).
1586
\warning \a done and \a total are not necessarily the size in
1587
bytes, since for large files these values might need to be
1588
"scaled" to avoid overflow.
1590
\sa get(), put(), QProgressBar
1594
\fn void QFtp::rawCommandReply(int replyCode, const QString &detail);
1596
This signal is emitted in response to the rawCommand() function.
1597
\a replyCode is the 3 digit reply code and \a detail is the text
1598
that follows the reply code.
1604
Connects to the FTP server \a host using port \a port.
1606
The stateChanged() signal is emitted when the state of the
1607
connecting process changes, e.g. to \c HostLookup, then \c
1608
Connecting, then \c Connected.
1610
The function does not block and returns immediately. The command
1611
is scheduled, and its execution is performed asynchronously. The
1612
function returns a unique identifier which is passed by
1613
commandStarted() and commandFinished().
1615
When the command is started the commandStarted() signal is
1616
emitted. When it is finished the commandFinished() signal is
1619
\sa stateChanged() commandStarted() commandFinished()
1621
int QFtp::connectToHost(const QString &host, quint16 port)
1623
d_func()->pi.transferConnectionExtended = true;
1626
cmds << QString::number((uint)port);
1627
return d_func()->addCommand(new QFtpCommand(ConnectToHost, cmds));
1631
Logs in to the FTP server with the username \a user and the
1632
password \a password.
1634
The stateChanged() signal is emitted when the state of the
1635
connecting process changes, e.g. to \c LoggedIn.
1637
The function does not block and returns immediately. The command
1638
is scheduled, and its execution is performed asynchronously. The
1639
function returns a unique identifier which is passed by
1640
commandStarted() and commandFinished().
1642
When the command is started the commandStarted() signal is
1643
emitted. When it is finished the commandFinished() signal is
1646
\sa commandStarted() commandFinished()
1648
int QFtp::login(const QString &user, const QString &password)
1651
cmds << (QString("USER ") + (user.isNull() ? QString("anonymous") : user) + "\r\n");
1652
cmds << (QString("PASS ") + (password.isNull() ? QString("anonymous@") : password) + "\r\n");
1653
return d_func()->addCommand(new QFtpCommand(Login, cmds));
1657
Closes the connection to the FTP server.
1659
The stateChanged() signal is emitted when the state of the
1660
connecting process changes, e.g. to \c Closing, then \c
1663
The function does not block and returns immediately. The command
1664
is scheduled, and its execution is performed asynchronously. The
1665
function returns a unique identifier which is passed by
1666
commandStarted() and commandFinished().
1668
When the command is started the commandStarted() signal is
1669
emitted. When it is finished the commandFinished() signal is
1672
\sa stateChanged() commandStarted() commandFinished()
1676
return d_func()->addCommand(new QFtpCommand(Close, QStringList("QUIT\r\n")));
1680
Sets the current FTP transfer mode to \a mode. The default is QFtp::Passive.
1682
\sa QFtp::TransferMode
1684
int QFtp::setTransferMode(TransferMode mode)
1686
d_func()->pi.transferConnectionExtended = true;
1687
d_func()->transferMode = mode;
1688
return d_func()->addCommand(new QFtpCommand(SetTransferMode, QStringList()));
1692
Enables use of the FTP proxy on host \a host and port \a
1693
port. Calling this function with \a host empty disables proxying.
1695
QFtp does not support FTP-over-HTTP proxy servers. Use QHttp for
1698
int QFtp::setProxy(const QString &host, quint16 port)
1701
args << host << QString::number(port);
1702
return d_func()->addCommand(new QFtpCommand(SetProxy, args));
1706
Lists the contents of directory \a dir on the FTP server. If \a
1707
dir is empty, it lists the contents of the current directory.
1709
The listInfo() signal is emitted for each directory entry found.
1711
The function does not block and returns immediately. The command
1712
is scheduled, and its execution is performed asynchronously. The
1713
function returns a unique identifier which is passed by
1714
commandStarted() and commandFinished().
1716
When the command is started the commandStarted() signal is
1717
emitted. When it is finished the commandFinished() signal is
1720
\sa listInfo() commandStarted() commandFinished()
1722
int QFtp::list(const QString &dir)
1725
cmds << "TYPE A\r\n";
1726
cmds << (d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
1730
cmds << ("LIST " + dir + "\r\n");
1731
return d_func()->addCommand(new QFtpCommand(List, cmds));
1735
Changes the working directory of the server to \a dir.
1737
The function does not block and returns immediately. The command
1738
is scheduled, and its execution is performed asynchronously. The
1739
function returns a unique identifier which is passed by
1740
commandStarted() and commandFinished().
1742
When the command is started the commandStarted() signal is
1743
emitted. When it is finished the commandFinished() signal is
1746
\sa commandStarted() commandFinished()
1748
int QFtp::cd(const QString &dir)
1750
return d_func()->addCommand(new QFtpCommand(Cd, QStringList("CWD " + dir + "\r\n")));
1754
Downloads the file \a file from the server.
1756
If \a dev is 0, then the readyRead() signal is emitted when there
1757
is data available to read. You can then read the data with the
1758
read() or readAll() functions.
1760
If \a dev is not 0, the data is written directly to the device \a
1761
dev. Make sure that the \a dev pointer is valid for the duration
1762
of the operation (it is safe to delete it when the
1763
commandFinished() signal is emitted). In this case the readyRead()
1764
signal is \e not emitted and you cannot read data with the
1765
readBlcok or readAll() functions.
1767
If you don't read the data immediately it becomes available, i.e.
1768
when the readyRead() signal is emitted, it is still available
1769
until the next command is started.
1771
For example, if you want to present the data to the user as soon
1772
as there is something available, connect to the readyRead() signal
1773
and read the data immediately. On the other hand, if you only want
1774
to work with the complete data, you can connect to the
1775
commandFinished() signal and read the data when the get() command
1778
The data is transferred as Binary or Ascii depending on the value
1781
The function does not block and returns immediately. The command
1782
is scheduled, and its execution is performed asynchronously. The
1783
function returns a unique identifier which is passed by
1784
commandStarted() and commandFinished().
1786
When the command is started the commandStarted() signal is
1787
emitted. When it is finished the commandFinished() signal is
1790
\sa readyRead() dataTransferProgress() commandStarted()
1793
int QFtp::get(const QString &file, QIODevice *dev, TransferType type)
1796
cmds << ("SIZE " + file + "\r\n");
1798
cmds << "TYPE I\r\n";
1800
cmds << "TYPE A\r\n";
1801
cmds << (d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
1802
cmds << ("RETR " + file + "\r\n");
1803
return d_func()->addCommand(new QFtpCommand(Get, cmds, dev));
1809
Writes a copy of the given \a data to the file called \a file on
1810
the server. The progress of the upload is reported by the
1811
dataTransferProgress() signal.
1813
The data is transferred as Binary or Ascii depending on the value
1816
The function does not block and returns immediately. The command
1817
is scheduled, and its execution is performed asynchronously. The
1818
function returns a unique identifier which is passed by
1819
commandStarted() and commandFinished().
1821
When the command is started the commandStarted() signal is
1822
emitted. When it is finished the commandFinished() signal is
1825
Since this function takes a copy of the \a data, you can discard
1826
your own copy when this function returns.
1828
\sa dataTransferProgress() commandStarted() commandFinished()
1830
int QFtp::put(const QByteArray &data, const QString &file, TransferType type)
1834
cmds << "TYPE I\r\n";
1836
cmds << "TYPE A\r\n";
1837
cmds << (d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
1838
cmds << ("ALLO " + QString::number(data.size()) + "\r\n");
1839
cmds << ("STOR " + file + "\r\n");
1840
return d_func()->addCommand(new QFtpCommand(Put, cmds, data));
1844
Reads the data from the IO device \a dev, and writes it to the
1845
file called \a file on the server. The data is read in chunks from
1846
the IO device, so this overload allows you to transmit large
1847
amounts of data without the need to read all the data into memory
1850
The data is transferred as Binary or Ascii depending on the value
1853
Make sure that the \a dev pointer is valid for the duration of the
1854
operation (it is safe to delete it when the commandFinished() is
1857
int QFtp::put(QIODevice *dev, const QString &file, TransferType type)
1861
cmds << "TYPE I\r\n";
1863
cmds << "TYPE A\r\n";
1864
cmds << (d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
1865
if (!dev->isSequential())
1866
cmds << ("ALLO " + QString::number(dev->size()) + "\r\n");
1867
cmds << ("STOR " + file + "\r\n");
1868
return d_func()->addCommand(new QFtpCommand(Put, cmds, dev));
1872
Deletes the file called \a file from the server.
1874
The function does not block and returns immediately. The command
1875
is scheduled, and its execution is performed asynchronously. The
1876
function returns a unique identifier which is passed by
1877
commandStarted() and commandFinished().
1879
When the command is started the commandStarted() signal is
1880
emitted. When it is finished the commandFinished() signal is
1883
\sa commandStarted() commandFinished()
1885
int QFtp::remove(const QString &file)
1887
return d_func()->addCommand(new QFtpCommand(Remove, QStringList("DELE " + file + "\r\n")));
1891
Creates a directory called \a dir on the server.
1893
The function does not block and returns immediately. The command
1894
is scheduled, and its execution is performed asynchronously. The
1895
function returns a unique identifier which is passed by
1896
commandStarted() and commandFinished().
1898
When the command is started the commandStarted() signal is
1899
emitted. When it is finished the commandFinished() signal is
1902
\sa commandStarted() commandFinished()
1904
int QFtp::mkdir(const QString &dir)
1906
return d_func()->addCommand(new QFtpCommand(Mkdir, QStringList("MKD " + dir + "\r\n")));
1910
Removes the directory called \a dir from the server.
1912
The function does not block and returns immediately. The command
1913
is scheduled, and its execution is performed asynchronously. The
1914
function returns a unique identifier which is passed by
1915
commandStarted() and commandFinished().
1917
When the command is started the commandStarted() signal is
1918
emitted. When it is finished the commandFinished() signal is
1921
\sa commandStarted() commandFinished()
1923
int QFtp::rmdir(const QString &dir)
1925
return d_func()->addCommand(new QFtpCommand(Rmdir, QStringList("RMD " + dir + "\r\n")));
1929
Renames the file called \a oldname to \a newname on the server.
1931
The function does not block and returns immediately. The command
1932
is scheduled, and its execution is performed asynchronously. The
1933
function returns a unique identifier which is passed by
1934
commandStarted() and commandFinished().
1936
When the command is started the commandStarted() signal is
1937
emitted. When it is finished the commandFinished() signal is
1940
\sa commandStarted() commandFinished()
1942
int QFtp::rename(const QString &oldname, const QString &newname)
1945
cmds << ("RNFR " + oldname + "\r\n");
1946
cmds << ("RNTO " + newname + "\r\n");
1947
return d_func()->addCommand(new QFtpCommand(Rename, cmds));
1951
Sends the raw FTP command \a command to the FTP server. This is
1952
useful for low-level FTP access. If the operation you wish to
1953
perform has an equivalent QFtp function, we recommend using the
1954
function instead of raw FTP commands since the functions are
1957
The function does not block and returns immediately. The command
1958
is scheduled, and its execution is performed asynchronously. The
1959
function returns a unique identifier which is passed by
1960
commandStarted() and commandFinished().
1962
When the command is started the commandStarted() signal is
1963
emitted. When it is finished the commandFinished() signal is
1966
\sa rawCommandReply() commandStarted() commandFinished()
1968
int QFtp::rawCommand(const QString &command)
1970
QString cmd = command.trimmed() + "\r\n";
1971
return d_func()->addCommand(new QFtpCommand(RawCommand, QStringList(cmd)));
1975
Returns the number of bytes that can be read from the data socket
1978
\sa get() readyRead() read() readAll()
1980
qint64 QFtp::bytesAvailable() const
1982
return d_func()->pi.dtp.bytesAvailable();
1985
/*! \fn qint64 QFtp::readBlock(char *data, quint64 maxlen)
1991
Reads \a maxlen bytes from the data socket into \a data and
1992
returns the number of bytes read. Returns -1 if an error occurred.
1994
\sa get() readyRead() bytesAvailable() readAll()
1996
qint64 QFtp::read(char *data, qint64 maxlen)
1998
return d_func()->pi.dtp.read(data, maxlen);
2002
Reads all the bytes available from the data socket and returns
2005
\sa get() readyRead() bytesAvailable() read()
2007
QByteArray QFtp::readAll()
2009
return d_func()->pi.dtp.readAll();
2013
Aborts the current command and deletes all scheduled commands.
2015
If there is an unfinished command (i.e. a command for which the
2016
commandStarted() signal has been emitted, but for which the
2017
commandFinished() signal has not been emitted), this function
2018
sends an \c ABORT command to the server. When the server replies
2019
that the command is aborted, the commandFinished() signal with the
2020
\c error argument set to \c true is emitted for the command. Due
2021
to timing issues, it is possible that the command had already
2022
finished before the abort request reached the server, in which
2023
case, the commandFinished() signal is emitted with the \c error
2024
argument set to \c false.
2026
For all other commands that are affected by the abort(), no
2027
signals are emitted.
2029
If you don't start further FTP commands directly after the
2030
abort(), there won't be any scheduled commands and the done()
2033
\warning Some FTP servers, for example the BSD FTP daemon (version
2034
0.3), wrongly return a positive reply even when an abort has
2035
occurred. For these servers the commandFinished() signal has its
2036
error flag set to \c false, even though the command did not
2037
complete successfully.
2039
\sa clearPendingCommands()
2043
if (d_func()->pending.isEmpty())
2046
clearPendingCommands();
2047
d_func()->pi.abort();
2051
Returns the identifier of the FTP command that is being executed
2052
or 0 if there is no command being executed.
2054
\sa currentCommand()
2056
int QFtp::currentId() const
2058
if (d_func()->pending.isEmpty())
2060
return d_func()->pending.first()->id;
2064
Returns the command type of the FTP command being executed or \c
2065
None if there is no command being executed.
2069
QFtp::Command QFtp::currentCommand() const
2071
if (d_func()->pending.isEmpty())
2073
return d_func()->pending.first()->command;
2077
Returns the QIODevice pointer that is used by the FTP command to read data
2078
from or store data to. If there is no current FTP command being executed or
2079
if the command does not use an IO device, this function returns 0.
2081
This function can be used to delete the QIODevice in the slot connected to
2082
the commandFinished() signal.
2086
QIODevice* QFtp::currentDevice() const
2088
if (d_func()->pending.isEmpty())
2090
QFtpCommand *c = d_func()->pending.first();
2097
Returns true if there are any commands scheduled that have not yet
2098
been executed; otherwise returns false.
2100
The command that is being executed is \e not considered as a
2103
\sa clearPendingCommands() currentId() currentCommand()
2105
bool QFtp::hasPendingCommands() const
2107
return d_func()->pending.count() > 1;
2111
Deletes all pending commands from the list of scheduled commands.
2112
This does not affect the command that is being executed. If you
2113
want to stop this this as well, use abort().
2115
\sa hasPendingCommands() abort()
2117
void QFtp::clearPendingCommands()
2119
// delete all entires except the first one
2120
while (d_func()->pending.count() > 1)
2121
delete d_func()->pending.takeLast();
2125
Returns the current state of the object. When the state changes,
2126
the stateChanged() signal is emitted.
2128
\sa State stateChanged()
2130
QFtp::State QFtp::state() const
2132
return d_func()->state;
2136
Returns the last error that occurred. This is useful to find out
2137
what when wrong when receiving a commandFinished() or a done()
2138
signal with the \c error argument set to \c true.
2140
If you start a new command, the error status is reset to \c NoError.
2142
QFtp::Error QFtp::error() const
2144
return d_func()->error;
2148
Returns a human-readable description of the last error that
2149
occurred. This is useful for presenting a error message to the
2150
user when receiving a commandFinished() or a done() signal with
2151
the \c error argument set to \c true.
2153
The error string is often (but not always) the reply from the
2154
server, so it is not always possible to translate the string. If
2155
the message comes from Qt, the string has already passed through
2158
QString QFtp::errorString() const
2160
return d_func()->errorString;
2165
void QFtpPrivate::startNextCommand()
2168
if (pending.isEmpty())
2170
QFtpCommand *c = pending.first();
2172
error = QFtp::NoError;
2173
errorString = QT_TRANSLATE_NOOP(QFtp, "Unknown error");
2175
if (q->bytesAvailable())
2176
q->readAll(); // clear the data
2177
emit q->commandStarted(c->id);
2179
// Proxy support, replace the Login argument in place, then fall
2181
if (c->command == QFtp::Login && !proxyHost.isEmpty()) {
2182
QString loginString = c->rawCmds.first().trimmed();
2183
loginString += "@" + host;
2184
if (port && port != 21)
2185
loginString += ":" + QString::number(port);
2186
loginString += "\r\n";
2187
c->rawCmds[0] = loginString;
2190
if (c->command == QFtp::SetTransferMode) {
2191
piFinished("Transfer mode set");
2192
} else if (c->command == QFtp::SetProxy) {
2193
proxyHost = c->rawCmds[0];
2194
proxyPort = c->rawCmds[1].toUInt();
2196
piFinished("Proxy set to " + proxyHost + ":" + QString::number(proxyPort));
2197
} else if (c->command == QFtp::ConnectToHost) {
2198
if (!proxyHost.isEmpty()) {
2199
host = c->rawCmds[0];
2200
port = c->rawCmds[1].toUInt();
2201
pi.connectToHost(proxyHost, proxyPort);
2203
pi.connectToHost(c->rawCmds[0], c->rawCmds[1].toUInt());
2206
if (c->command == QFtp::Put) {
2208
pi.dtp.setData(c->data.ba);
2209
pi.dtp.setBytesTotal(c->data.ba->size());
2210
} else if (c->data.dev && (c->data.dev->isOpen() || c->data.dev->open(QIODevice::ReadOnly))) {
2211
pi.dtp.setDevice(c->data.dev);
2212
if (c->data.dev->isSequential())
2213
pi.dtp.setBytesTotal(0);
2215
pi.dtp.setBytesTotal(c->data.dev->size());
2217
} else if (c->command == QFtp::Get) {
2218
if (!c->is_ba && c->data.dev) {
2219
pi.dtp.setDevice(c->data.dev);
2221
} else if (c->command == QFtp::Close) {
2222
state = QFtp::Closing;
2223
emit q->stateChanged(state);
2225
pi.sendCommands(c->rawCmds);
2231
void QFtpPrivate::piFinished(const QString&)
2233
if (pending.isEmpty())
2235
QFtpCommand *c = pending.first();
2237
if (c->command == QFtp::Close) {
2238
// The order of in which the slots are called is arbitrary, so
2239
// disconnect the SIGNAL-SIGNAL temporary to make sure that we
2240
// don't get the commandFinished() signal before the stateChanged()
2242
if (state != QFtp::Unconnected) {
2243
close_waitForStateChange = true;
2247
emit q_func()->commandFinished(c->id, false);
2248
pending.removeFirst();
2252
if (pending.isEmpty()) {
2253
emit q_func()->done(false);
2261
void QFtpPrivate::piError(int errorCode, const QString &text)
2264
QFtpCommand *c = pending.first();
2267
if (c->command == QFtp::Get && pi.currentCommand().startsWith("SIZE ")) {
2268
pi.dtp.setBytesTotal(-1);
2270
} else if (c->command==QFtp::Put && pi.currentCommand().startsWith("ALLO ")) {
2274
error = QFtp::Error(errorCode);
2275
switch (q->currentCommand()) {
2276
case QFtp::ConnectToHost:
2277
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Connecting to host failed:\n%1"))
2281
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Login failed:\n%1"))
2285
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Listing directory failed:\n%1"))
2289
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Changing directory failed:\n%1"))
2293
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Downloading file failed:\n%1"))
2297
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Uploading file failed:\n%1"))
2301
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Removing file failed:\n%1"))
2305
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Creating directory failed:\n%1"))
2309
errorString = QString(QT_TRANSLATE_NOOP("QFtp", "Removing directory failed:\n%1"))
2317
pi.clearPendingCommands();
2318
q->clearPendingCommands();
2319
emit q->commandFinished(c->id, true);
2321
pending.removeFirst();
2323
if (pending.isEmpty())
2331
void QFtpPrivate::piConnectState(int connectState)
2333
state = QFtp::State(connectState);
2334
emit q_func()->stateChanged(state);
2335
if (close_waitForStateChange) {
2336
close_waitForStateChange = false;
2337
piFinished(QT_TRANSLATE_NOOP("QFtp", "Connection closed"));
2343
void QFtpPrivate::piFtpReply(int code, const QString &text)
2345
if (q_func()->currentCommand() == QFtp::RawCommand) {
2346
pi.rawCommand = true;
2347
emit q_func()->rawCommandReply(code, text);
2362
#include "moc_qftp.cpp"
2364
#endif // QT_NO_NETWORKPROTOCOL_FTP