qftp.cpp
来自「QT写的自动更新程序 自认为不错 请大家参考」· C++ 代码 · 共 1,988 行 · 第 1/5 页
CPP
1,988 行
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];
while (!data.dev->atEnd() && socket->bytesToWrite() == 0) {
qint64 read = data.dev->read(buf, blockSize);
#if defined(QFTPDTP_DEBUG)
qDebug("QFtpDTP::writeData: write() of size %lli bytes", read);
#endif
socket->write(buf, read);
if (!data.dev)
return; // this can happen when a command is aborted
}
if (data.dev->atEnd()) {
if (bytesDone == 0 && socket->bytesToWrite() == 0)
emit dataTransferProgress(0, bytesTotal);
socket->close();
clearData();
} else {
callWriteData = true;
}
}
}
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)
{
// Adjust for future tolerance.
const int futureTolerance = 86400;
if (dateTime->secsTo(QDateTime::currentDateTime()) < -futureTolerance) {
QDate d = dateTime->date();
d.setYMD(d.year() - 1, d.month(), d.day());
dateTime->setDate(d);
}
}
static void _q_parseUnixDir(const QStringList &tokens, const QString &userName, QUrlInfo *info)
{
// Unix style, 7 + 1 entries
// -rw-r--r-- 1 ftp ftp 17358091 Aug 10 2004 qt-x11-free-3.3.3.tar.gz
// drwxr-xr-x 3 ftp ftp 4096 Apr 14 2000 compiled-examples
// lrwxrwxrwx 1 ftp ftp 9 Oct 29 2005 qtscape -> qtmozilla
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);
}
// Resolve filename
QString name = tokens.at(7);
if (info->isSymLink()) {
int linkPos = name.indexOf(QLatin1String(" ->"));
if (linkPos != -1)
name.resize(linkPos);
}
info->setName(name);
// Resolve owner & group
info->setOwner(tokens.at(3));
info->setGroup(tokens.at(4));
// Resolve size
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();
// Resolve the modification date by parsing all possible formats
QDateTime dateTime;
int n = 0;
#ifndef QT_NO_DATESTRING
do {
dateTime = QDateTime::fromString(dateString, formats.at(n++));
} while (n < formats.size() && (!dateTime.isValid()));
#endif
if (n == 2 || n == 4) {
// Guess the year.
dateTime.setDate(QDate(QDate::currentDate().year(),
dateTime.date().month(),
dateTime.date().day()));
_q_fixupDateTime(&dateTime);
}
if (dateTime.isValid())
info->setLastModified(dateTime);
// Resolve permissions
int permissions = 0;
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)
{
// DOS style, 3 + 1 entries
// 01-16-02 11:14AM <DIR> epsgroup
// 06-05-03 03:19PM 1973 readme.txt
if (tokens.size() != 4)
return;
Q_UNUSED(userName);
QString name = tokens.at(3);
info->setName(name);
info->setSymLink(name.toLower().endsWith(QLatin1String(".lnk")));
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());
}
// Note: We cannot use QFileInfo; permissions are for the server-side
// machine, and QFileInfo's behavior depends on the local platform.
int permissions = QUrlInfo::ReadOwner | QUrlInfo::WriteOwner
| QUrlInfo::ReadGroup | QUrlInfo::WriteGroup
| QUrlInfo::ReadOther | QUrlInfo::WriteOther;
QString ext;
int extIndex = name.lastIndexOf(QLatin1Char('.'));
if (extIndex != -1)
ext = name.mid(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 = QDateTime::fromString(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::fromLatin1(buffer).trimmed();
// Unix style FTP servers
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;
}
// DOS style FTP servers
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;
}
// Unsupported
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::AbortStarted) {
// discard data
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 {
// some FTP servers don't return a 550 if the file or directory
// does not exist, but rather write a text to the data socket
// -- try to catch these cases
if (line.endsWith("No such file or directory\r\n"))
err = QString::fromLatin1(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) {
// a read following a readyRead() signal will
// never fail.
return;
}
ba.resize(bytesRead);
bytesDone += bytesRead;
#if defined(QFTPDTP_DEBUG)
qDebug("QFtpDTP read: %lli bytes (total %lli bytes)", bytesRead, bytesDone);
#endif
if (data.dev) // make sure it wasn't deleted in the slot
data.dev->write(ba);
emit dataTransferProgress(bytesDone, bytesTotal);
// Need to loop; dataTransferProgress is often connected to
// slots that update the GUI (e.g., progress bar values), and
// if events are processed, more data may have arrived.
} 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();
}
bytesFromSocket = socket->readAll();
#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(error(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 = 0;
//wybo added
bytesDone = 0;
}
/**********************************************************************
*
* QFtpPI implemenatation
*
*********************************************************************/
QFtpPI::QFtpPI(QObject *parent) :
QObject(parent),
rawCommand(false),
transferConnectionExtended(true),
dtp(this),
commandSocket(0),
state(Begin), abortState(None),
currentCmd(QString()),
waitForDtpToConnect(false),
waitForDtpToClose(false)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?