        ftpReadyRead();
}

void QNetworkAccessFtpBackend::ftpConnectionReady(QNetworkAccessCache::CacheableObject *o)
{
    ftp = static_cast<QNetworkAccessCachedFtpConnection *>(o);
    connect(ftp, SIGNAL(done(bool)), SLOT(ftpDone()));
    connect(ftp, SIGNAL(rawCommandReply(int,QString)), SLOT(ftpRawCommandReply(int,QString)));
    connect(ftp, SIGNAL(readyRead()), SLOT(ftpReadyRead()));

    // is the login process done already?
    if (ftp->state() == QFtp::LoggedIn)
        ftpDone();

    // no, defer the actual operation until after we've logged in
}

void QNetworkAccessFtpBackend::disconnectFromFtp()
{
    state = Disconnecting;

    if (ftp) {
        disconnect(ftp, 0, this, 0);

        QByteArray key = makeCacheKey(url());
        QNetworkAccessManagerPrivate::getObjectCache(this)->releaseEntry(key);

        ftp = 0;
    }
}

void QNetworkAccessFtpBackend::ftpDone()
{
    // the last command we sent is done
    if (state == LoggingIn && ftp->state()!= QFtp::LoggedIn) {
        if (ftp->state() == QFtp::Connected) {
            // the login did not succeed
            QUrl newUrl = url();
            newUrl.setUserInfo(QString());
            setUrl(newUrl);

            QAuthenticator auth;
            authenticationRequired(&auth);

            if (!auth.isNull()) {
                // try again:
                newUrl.setUserName(auth.user());
                ftp->login(auth.user(), auth.password());
                return;
            }

            error(QNetworkReply::AuthenticationRequiredError,
                  tr("Logging in to %1 failed: authentication required")
                 .arg(url().host()));
        } else {
            // we did not connect
            QNetworkReply::NetworkError code;
            switch (ftp->error()) {
            case QFtp::HostNotFound:
                code = QNetworkReply::HostNotFoundError;
                break;

            case QFtp::ConnectionRefused:
                code = QNetworkReply::ConnectionRefusedError;
                break;

            default:
                code = QNetworkReply::ProtocolFailure;
                break;
            }

            error(code, ftp->errorString());
        }

        // we're not connected, so remove the cache entry:
        QByteArray key = makeCacheKey(url());
        QNetworkAccessManagerPrivate::getObjectCache(this)->removeEntry(key);

        disconnect(ftp, 0, this, 0);
        ftp->dispose();
        ftp = 0;

        state = Disconnecting;
        finished();
        return;
    }

    // check for errors:
    if (ftp->error()!= QFtp::NoError) {
        QString msg;
        if (operation() == QNetworkAccessManager::GetOperation)
            msg = tr("Error while downloading %1: %2");
        else
            msg = tr("Error while uploading %1: %2");
        msg = msg.arg(url().toString(), ftp->errorString());

        if (state == Statting)
            // file probably doesn't exist
            error(QNetworkReply::ContentNotFoundError,  msg);
        else
            error(QNetworkReply::ContentAccessDenied, msg);

        disconnectFromFtp();
        finished();
    }

    if (state == LoggingIn) {
        state = CheckingFeatures;
        if (operation() == QNetworkAccessManager::GetOperation) {
            // send help command to find out if server supports "SIZE" and "MDTM"
            QString command = url().path();
            command.prepend(QLatin1String("%1 "));
            helpId = ftp->rawCommand(QLatin1String("HELP")); // get supported commands
        } else {
            ftpDone();
        }
    } else if (state == CheckingFeatures) {
        state = Statting;
        if (operation() == QNetworkAccessManager::GetOperation) {
            // logged in successfully, send the stat requests (if supported)
            QString command = url().path();
            command.prepend(QLatin1String("%1 "));
            if (supportsSize) {
                ftp->rawCommand(QLatin1String("TYPE I"));
                sizeId = ftp->rawCommand(command.arg(QLatin1String("SIZE"))); // get size
            }
            if (supportsMdtm)
                mdtmId = ftp->rawCommand(command.arg(QLatin1String("MDTM"))); // get modified time
            if (!supportsSize &&!supportsMdtm)
                ftpDone();      // no commands sent, move to the next state
        } else {
            ftpDone();
        }
    } else if (state == Statting) {
        // statted successfully, send the actual request
        emit metaDataChanged();
        state = Transferring;

        QFtp::TransferType type = QFtp::Binary;
        if (operation() == QNetworkAccessManager::GetOperation) {
            setCachingEnabled(true);
            ftp->get(url().path(), 0, type);
        } else {
            ftp->put(uploadDevice, url().path(), type);
        }

    } else if (state == Transferring) {
        // upload or download finished
        disconnectFromFtp();
        finished();
    }
}

void QNetworkAccessFtpBackend::ftpReadyRead()
{
    QByteArray data = ftp->readAll();
    QByteDataBuffer list;
    list.append(data);
    data.clear(); // important because of implicit sharing!
    writeDownstreamData(list);
}

void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text)
{
    //qDebug() << "FTP reply:" << code << text;
    int id = ftp->currentId();

    if ((id == helpId) && ((code == 200) || (code == 214))) {     // supported commands
        // the "FEAT" ftp command would be nice here, but it is not part of the
        // initial FTP RFC 959, neither ar "SIZE" nor "MDTM" (they are all specified
        // in RFC 3659)
        if (text.contains(QLatin1String("SIZE"), Qt::CaseSensitive))
            supportsSize = true;
        if (text.contains(QLatin1String("MDTM"), Qt::CaseSensitive))
            supportsMdtm = true;
    } else if (code == 213) {          // file status
        if (id == sizeId) {
            // reply to the size command
            setHeader(QNetworkRequest::ContentLengthHeader, text.toLongLong());
#ifndef QT_NO_DATESTRING
        } else if (id == mdtmId) {
            QDateTime dt = QDateTime::fromString(text, QLatin1String("yyyyMMddHHmmss"));
            setHeader(QNetworkRequest::LastModifiedHeader, dt);
#endif
        }
    }
}

QT_END_NAMESPACE

#endif // QT_NO_FTP
Thanks to Stan Parchin for sending me the above link.
Can the message of the world’s vanished religions ever be understood? The urge to do so is irresistible when the art that they inspired dazzles us. “The Doors of Heaven,” and the important volume edited by the exhibition curator, Marc Etienne, purport to explain the “World Perceptions in Ancient Egypt,” as the subtitle puts it.
The latest on the arts, coverage of live events, critical reviews, multimedia extravaganzas and much more. Join the discussion.
But reconstructing theological concepts through the partly preserved texts of a dead language is not an easy task. And, more importantly, finding the secret of the illumination that we surmise here and there in the art of a faith that died out around the late third century A.D. seems beyond our reach.
Yet, the investigation is gripping. Never mind the disappointing artistic selection, and the arid prose bristling with weird-sounding names and technical details required by the nature of the undertaking. More disturbing are its limitations, which the scholarly tone of the discourse cannot conceal.
Deities central to the faith turn out, on closer inspection, to be deeply enigmatic.
See the above page for the full story.Facebook today announced that it is shutting down it’s text-based virtual personal digital assistant M which was first introduced back in 2015. The human-enhanced M was available through bots in Facebook Messenger to just 2