diff --git a/src/core/kfileitem.h b/src/core/kfileitem.h index 1754853e..720e998a 100644 --- a/src/core/kfileitem.h +++ b/src/core/kfileitem.h @@ -1,576 +1,576 @@ /* This file is part of the KDE project Copyright (C) 1999-2006 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KFILEITEM_H #define KFILEITEM_H #include "kiocore_export.h" #include #include #include #include #include #include #include #include #include class KFileItemPrivate; /** * A KFileItem is a generic class to handle a file, local or remote. * In particular, it makes it easier to handle the result of KIO::listDir * (UDSEntry isn't very friendly to use). * It includes many file attributes such as mimetype, icon, text, mode, link... * * KFileItem is implicitly shared, i.e. it can be used as a value and copied around at almost no cost. */ class KIOCORE_EXPORT KFileItem { public: enum { Unknown = static_cast(-1) }; /** * The timestamps associated with a file. * - ModificationTime: the time the file's contents were last modified * - AccessTime: the time the file was last accessed (last read or written to) * - CreationTime: the time the file was created */ enum FileTimes { // warning: don't change without looking at the Private class ModificationTime = 0, AccessTime = 1, CreationTime = 2 //ChangeTime }; /** * Null KFileItem. Doesn't represent any file, only exists for convenience. */ KFileItem(); /** * Creates an item representing a file, from a UDSEntry. * This is the preferred constructor when using KIO::listDir(). * * @param entry the KIO entry used to get the file, contains info about it * @param itemOrDirUrl the URL of the item or of the directory containing this item (see urlIsDirectory). * @param delayedMimeTypes specifies if the mimetype of the given * URL should be determined immediately or on demand. * See the bool delayedMimeTypes in the KDirLister constructor. * @param urlIsDirectory specifies if the url is just the directory of the * fileitem and the filename from the UDSEntry should be used. * * When creating KFileItems out of the UDSEntry emitted by a KIO list job, * use KFileItem(entry, listjob->url(), delayedMimeTypes, true); */ KFileItem(const KIO::UDSEntry &entry, const QUrl &itemOrDirUrl, bool delayedMimeTypes = false, bool urlIsDirectory = false); /** * Creates an item representing a file, from all the necessary info for it. * @param mode the file mode (according to stat() (e.g. S_IFDIR...) * Set to KFileItem::Unknown if unknown. For local files, KFileItem will use stat(). * @param permissions the access permissions * If you set both the mode and the permissions, you save a ::stat() for * local files. * Set to KFileItem::Unknown if you don't know the mode or the permission. * @param url the file url * * @param delayedMimeTypes specify if the mimetype of the given URL * should be determined immediately or on demand * @deprecated since 5.0. Most callers gave Unknown for mode and permissions, * so just port to KFileItem(url) and setDelayedMimeTypes(true) if necessary. */ #ifndef KIOCORE_NO_DEPRECATED KIOCORE_DEPRECATED KFileItem(mode_t mode, mode_t permissions, const QUrl &url, bool delayedMimeTypes = false); #endif /** * Creates an item representing a file, for which the mimetype is already known. * @param url the file url * @param mimeType the name of the file's mimetype * @param mode the mode (S_IFDIR...) */ KFileItem(const QUrl &url, const QString &mimeType = QString(), mode_t mode = KFileItem::Unknown); // KF6 TODO: explicit! /** * Copy constructor */ KFileItem(const KFileItem &other); /** * Assignment operator */ KFileItem &operator=(const KFileItem &other); /** * Destructs the KFileItem. */ ~KFileItem(); /** * Throw away and re-read (for local files) all information about the file. * This is called when the _file_ changes. */ void refresh(); /** * Re-reads mimetype information. * This is called when the mimetype database changes. */ void refreshMimeType(); /** * Sets mimetype determination to be immediate or on demand. * Call this after the constructor, and before using any mimetype-related method. * @since 5.0 */ void setDelayedMimeTypes(bool b); /** * Returns the url of the file. * @return the url of the file */ QUrl url() const; /** * Sets the item's URL. Do not call unless you know what you are doing! * (used for example when an item got renamed). * @param url the item's URL */ void setUrl(const QUrl &url); /** * Sets the item's local path (UDS_LOCAL_PATH). Do not call unless you know what you are doing! * This won't change the item's name or URL. * (used for example when an item got renamed). * @param path the item's local path * @since 5.20 */ void setLocalPath(const QString &path); /** * Sets the item's name (i.e. the filename). * This is automatically done by setUrl, to set the name from the URL's fileName(). * This method is provided for some special cases like relative paths as names (KFindPart) * @param name the item's name */ void setName(const QString &name); /** * Returns the permissions of the file (stat.st_mode containing only permissions). * @return the permissions of the file */ mode_t permissions() const; /** * Returns the access permissions for the file as a string. * @return the access persmission as string */ QString permissionsString() const; /** * Tells if the file has extended access level information ( Posix ACL ) * @return true if the file has extend ACL information or false if it hasn't */ bool hasExtendedACL() const; /** * Returns the access control list for the file. * @return the access control list as a KACL */ KACL ACL() const; /** * Returns the default access control list for the directory. * @return the default access control list as a KACL */ KACL defaultACL() const; /** * Returns the file type (stat.st_mode containing only S_IFDIR, S_IFLNK, ...). * @return the file type */ mode_t mode() const; /** * Returns the owner of the file. * @return the file's owner */ QString user() const; /** * Returns the group of the file. * @return the file's group */ QString group() const; /** * Returns true if this item represents a link in the UNIX sense of * a link. * @return true if the file is a link */ bool isLink() const; /** * Returns true if this item represents a directory. * @return true if the item is a directory */ bool isDir() const; /** - * Returns true if this item represents a file (and not a a directory) + * Returns true if this item represents a file (and not a directory) * @return true if the item is a file */ bool isFile() const; /** * Checks whether the file or directory is readable. In some cases * (remote files), we may return true even though it can't be read. * @return true if the file can be read - more precisely, * false if we know for sure it can't */ bool isReadable() const; /** * Checks whether the file or directory is writable. In some cases * (remote files), we may return true even though it can't be written to. * @return true if the file or directory can be written to - more precisely, * false if we know for sure it can't */ bool isWritable() const; /** * Checks whether the file is hidden. * @return true if the file is hidden. */ bool isHidden() const; /** * @return true if the file is a remote URL, or a local file on a network mount. * It will return false only for really-local file systems. * @since 4.7.4 */ bool isSlow() const; /** * Checks whether the file is a readable local .desktop file, * i.e. a file whose path can be given to KDesktopFile * @return true if the file is a desktop file. * @since 4.1 */ bool isDesktopFile() const; /** * Returns the link destination if isLink() == true. * @return the link destination. QString() if the item is not a link */ QString linkDest() const; /** * Returns the target url of the file, which is the same as url() * in cases where the slave doesn't specify UDS_TARGET_URL * @return the target url. * @since 4.1 */ QUrl targetUrl() const; /** * Returns the local path if isLocalFile() == true or the KIO item has * a UDS_LOCAL_PATH atom. * @return the item local path, or QString() if not known */ QString localPath() const; /** * Returns the size of the file, if known. * @return the file size, or 0 if not known */ KIO::filesize_t size() const; /** * Requests the modification, access or creation time, depending on @p which. * @param which the timestamp * @return the time asked for, QDateTime() if not available * @see timeString() */ QDateTime time(FileTimes which) const; /** * Requests the modification, access or creation time as a string, depending * on @p which. * @param which the timestamp * @returns a formatted string of the requested time. * @see time */ QString timeString(FileTimes which = ModificationTime) const; #ifndef KIOCORE_NO_DEPRECATED KIOCORE_DEPRECATED QString timeString(unsigned int which) const; #endif /** * Returns true if the file is a local file. * @return true if the file is local, false otherwise */ bool isLocalFile() const; /** * Returns the text of the file item. * It's not exactly the filename since some decoding happens ('%2F'->'/'). * @return the text of the file item */ QString text() const; /** * Return the name of the file item (without a path). * Similar to text(), but unencoded, i.e. the original name. * @param lowerCase if true, the name will be returned in lower case, * which is useful to speed up sorting by name, case insensitively. * @return the file's name */ QString name(bool lowerCase = false) const; /** * Returns the mimetype of the file item. * If @p delayedMimeTypes was used in the constructor, this will determine * the mimetype first. Equivalent to determineMimeType()->name() * @return the mime type of the file */ QString mimetype() const; /** * Returns the mimetype of the file item. * If delayedMimeTypes was used in the constructor, this will determine * the mimetype first. * @return the mime type */ QMimeType determineMimeType() const; /** * Returns the currently known mimetype of the file item. * This will not try to determine the mimetype if unknown. * @return the known mime type */ QMimeType currentMimeType() const; /** * @return true if we have determined the final icon of this file already. * @since 4.10.2 */ bool isFinalIconKnown() const; /** * @return true if we have determined the mimetype of this file already, * i.e. if determineMimeType() will be fast. Otherwise it will have to * find what the mimetype is, which is a possibly slow operation; usually * this is delayed until necessary. */ bool isMimeTypeKnown() const; /** * Returns the user-readable string representing the type of this file, * like "OpenDocument Text File". * @return the type of this KFileItem */ QString mimeComment() const; /** * Returns the full path name to the icon that represents * this mime type. * @return iconName the name of the file's icon */ QString iconName() const; /** * Returns the overlays (bitfield of KIconLoader::*Overlay flags) that are used * for this item's pixmap. Overlays are used to show for example, whether * a file can be modified. * @return the overlays of the pixmap */ QStringList overlays() const; /** * A comment which can contain anything - even rich text. It will * simply be displayed to the user as is. * * @since 4.6 */ QString comment() const; /** * Returns the string to be displayed in the statusbar, * e.g. when the mouse is over this item * @return the status bar information */ QString getStatusBarInfo() const; /** * Returns true if files can be dropped over this item. * Contrary to popular belief, not only dirs will return true :) * Executables, .desktop files, will do so as well. * @return true if you can drop files over the item * * @deprecated This logic is application-dependent, the behavior described above * mostly makes sense for file managers only. * KDirModel has setDropsAllowed for similar (but configurable) logic. */ #ifndef KIOCORE_NO_DEPRECATED KIOCORE_DEPRECATED bool acceptsDrops() const; #endif /** * Returns the UDS entry. Used by the tree view to access all details * by position. * @return the UDS entry */ KIO::UDSEntry entry() const; /** * Return true if this item is a regular file, * false otherwise (directory, link, character/block device, fifo, socket) * @since 4.3 */ bool isRegularFile() const; /** * Somewhat like a comparison operator, but more explicit, * and it can detect that two fileitems differ if any property of the file item * has changed (file size, modification date, etc.). Two items are equal if * all properties are equal. In contrast, operator== only compares URLs. * @param item the item to compare * @return true if all values are equal */ bool cmp(const KFileItem &item) const; /** * Returns true if both items share the same URL. */ bool operator==(const KFileItem &other) const; /** * Returns true if both items do not share the same URL. */ bool operator!=(const KFileItem &other) const; /** * Converts this KFileItem to a QVariant, this allows to use KFileItem * in QVariant() constructor */ operator QVariant() const; /** * @deprecated simply use '=' */ #ifndef KIOCORE_NO_DEPRECATED KIOCORE_DEPRECATED void assign(const KFileItem &item); #endif /** * Tries to give a local URL for this file item if possible. * The given boolean indicates if the returned url is local or not. * \since 4.6 */ QUrl mostLocalUrl(bool *local = nullptr) const; /** * @deprecated since 5.0 add '&' in front of your boolean argument */ #ifndef KIOCORE_NO_DEPRECATED QUrl mostLocalUrl(bool &local) const { return mostLocalUrl(&local); } #endif /** * Return true if default-constructed */ bool isNull() const; private: QSharedDataPointer d; /** * Hides the file. */ void setHidden(); private: KIOCORE_EXPORT friend QDataStream &operator<< (QDataStream &s, const KFileItem &a); KIOCORE_EXPORT friend QDataStream &operator>> (QDataStream &s, KFileItem &a); friend class KFileItemTest; friend class KCoreDirListerCache; }; Q_DECLARE_METATYPE(KFileItem) Q_DECLARE_TYPEINFO(KFileItem, Q_MOVABLE_TYPE); inline uint qHash(const KFileItem &item) { return qHash(item.url()); } /** * List of KFileItems, which adds a few helper * methods to QList. */ class KIOCORE_EXPORT KFileItemList : public QList { public: /// Creates an empty list of file items. KFileItemList(); /// Creates a new KFileItemList from a QList of file @p items. KFileItemList(const QList &items); /** * Find a KFileItem by name and return it. * @return the item with the given name, or a null-item if none was found * (see KFileItem::isNull()) */ KFileItem findByName(const QString &fileName) const; /** * Find a KFileItem by URL and return it. * @return the item with the given URL, or a null-item if none was found * (see KFileItem::isNull()) */ KFileItem findByUrl(const QUrl &url) const; /// @return the list of URLs that those items represent QList urlList() const; /// @return the list of target URLs that those items represent /// @since 4.2 QList targetUrlList() const; // TODO KDE-5 add d pointer here so that we can merge KFileItemListProperties into KFileItemList }; KIOCORE_EXPORT QDataStream &operator<< (QDataStream &s, const KFileItem &a); KIOCORE_EXPORT QDataStream &operator>> (QDataStream &s, KFileItem &a); /** * Support for qDebug() << aFileItem * \since 4.4 */ KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KFileItem &item); #endif diff --git a/src/core/klocalsocket.cpp b/src/core/klocalsocket.cpp index 80ca5dbc..7ab264ce 100644 --- a/src/core/klocalsocket.cpp +++ b/src/core/klocalsocket.cpp @@ -1,228 +1,228 @@ /* * This file is part of the KDE libraries * Copyright (C) 2007 Thiago Macieira * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "klocalsocket.h" #include "klocalsocket_p.h" #include "kiocoredebug.h" #include //#define LocalSocket (QAbstractSocket::SocketType(int(QAbstractSocket::UdpSocket) + 1)) void KLocalSocketPrivate::emitError(QAbstractSocket::SocketError error, const QString &errorString) { q->setSocketState(QAbstractSocket::UnconnectedState); q->setSocketError(error); q->setErrorString(errorString); emit q->stateChanged(QAbstractSocket::UnconnectedState); emit q->error(error); } void KLocalSocketServerPrivate::emitError(QAbstractSocket::SocketError an_error, const QString &an_errorString) { error = an_error; errorString = an_errorString; } KLocalSocket::KLocalSocket(QObject *parent) : QTcpSocket(parent), d(new KLocalSocketPrivate(this)) { } KLocalSocket::~KLocalSocket() { delete d; // parent's destructor closes the socket } void KLocalSocket::connectToPath(const QString &path, OpenMode mode) { // cheat: connectToHost(path, UnixSocket, mode); } void KLocalSocket::connectToPath(const QString &path, LocalSocketType type, OpenMode mode) { // cheat: connectToHost(path, type, mode); } void KLocalSocket::connectToHostImplementation(const QString &path, quint16 type, OpenMode mode) { if (state() == ConnectedState || state() == ConnectingState) { return; } d->localPath.clear(); d->peerPath.clear(); setSocketState(ConnectingState); emit stateChanged(ConnectingState); d->connectToPath(path, LocalSocketType(type), mode); } void KLocalSocket::disconnectFromHostImplementation() { QTcpSocket::disconnectFromHost(); d->peerPath.clear(); d->localPath.clear(); d->type = UnknownLocalSocketType; } void KLocalSocket::disconnectFromPath() { // cheat: disconnectFromHost(); } KLocalSocket::LocalSocketType KLocalSocket::localSocketType() const { return d->type; } QString KLocalSocket::localPath() const { return d->localPath; } QString KLocalSocket::peerPath() const { return d->peerPath; } KLocalSocketServerPrivate::KLocalSocketServerPrivate(KLocalSocketServer *qq) : q(qq), descriptor(-1), maxPendingConnections(30), state(QAbstractSocket::UnconnectedState), error(QAbstractSocket::UnknownSocketError), type(KLocalSocket::UnknownLocalSocketType), readNotifier(nullptr) { } KLocalSocketServer::KLocalSocketServer(QObject *parent) : QObject(parent), d(new KLocalSocketServerPrivate(this)) { } KLocalSocketServer::~KLocalSocketServer() { close(); delete d; } bool KLocalSocketServer::isListening() const { return d->state == QAbstractSocket::ListeningState; } bool KLocalSocketServer::listen(const QString &path, KLocalSocket::LocalSocketType type) { if (d->state == QAbstractSocket::ListeningState) { return false; // already created } if (!d->listen(path, type)) { // the private set the error code return false; } d->localPath = path; return true; } void KLocalSocketServer::close() { d->close(); } void KLocalSocketServer::setMaxPendingConnections(int numConnections) { if (numConnections >= 0) { d->maxPendingConnections = numConnections; d->readNotifier->setEnabled(d->pendingConnections.size() < d->maxPendingConnections); } else { qCWarning(KIO_CORE, "KLocalSocketServer::setMaxPendingConnections: cannot set to a negative number"); } } int KLocalSocketServer::maxPendingConnections() const { return d->maxPendingConnections; } KLocalSocket::LocalSocketType KLocalSocketServer::localSocketType() const { return d->type; } QString KLocalSocketServer::localPath() const { return d->localPath; } bool KLocalSocketServer::waitForNewConnection(int msec, bool *timedOut) { if (!isListening()) { - return false; // can't wait if we're not not listening + return false; // can't wait if we're not listening } return d->waitForNewConnection(msec, timedOut); } bool KLocalSocketServer::hasPendingConnections() const { return !d->pendingConnections.isEmpty(); } KLocalSocket *KLocalSocketServer::nextPendingConnection() { if (hasPendingConnections()) { d->readNotifier->setEnabled((d->pendingConnections.size() - 1) < d->maxPendingConnections); return d->pendingConnections.dequeue(); } return nullptr; } void KLocalSocketServer::incomingConnection(int descriptor) { KLocalSocket *socket = new KLocalSocket(this); KLocalSocketPrivate *socket_d = KLocalSocketPrivate::d(socket); socket_d->localPath = d->localPath; socket_d->type = d->type; socket->setSocketDescriptor(descriptor, QAbstractSocket::ConnectedState, QIODevice::ReadWrite); d->pendingConnections.enqueue(socket); emit newConnection(); } QAbstractSocket::SocketError KLocalSocketServer::serverError() const { return d->error; } QString KLocalSocketServer::errorString() const { return d->errorString; } #include "moc_klocalsocket.cpp" diff --git a/src/core/tcpslavebase.cpp b/src/core/tcpslavebase.cpp index 7a1bae25..5acd0af9 100644 --- a/src/core/tcpslavebase.cpp +++ b/src/core/tcpslavebase.cpp @@ -1,1001 +1,1001 @@ /* * Copyright (C) 2000 Alex Zepeda * Copyright (C) 2001-2003 George Staikos * Copyright (C) 2001 Dawit Alemayehu * Copyright (C) 2007,2008 Andreas Hartmetz * Copyright (C) 2008 Roland Harnau * Copyright (C) 2010 Richard Moore * * This file is part of the KDE project * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "tcpslavebase.h" #include "kiocoredebug.h" #include #include #include #include #include #include #include #include #include #include #include using namespace KIO; //using namespace KNetwork; namespace KIO { Q_DECLARE_OPERATORS_FOR_FLAGS(TCPSlaveBase::SslResult) } //TODO Proxy support whichever way works; KPAC reportedly does *not* work. //NOTE kded_proxyscout may or may not be interesting //TODO resurrect SSL session recycling; this means save the session on disconnect and look //for a reusable session on connect. Consider how HTTP persistent connections interact with that. //TODO in case we support SSL-lessness we need static KTcpSocket::sslAvailable() and check it //in most places we ATM check for d->isSSL. //TODO check if d->isBlocking is honored everywhere it makes sense //TODO fold KSSLSetting and KSSLCertificateHome into KSslSettings and use that everywhere. //TODO recognize partially encrypted websites as "somewhat safe" /* List of dialogs/messageboxes we need to use (current code location in parentheses) - Can the "dontAskAgainName" thing be improved? - "SSLCertDialog" [select client cert] (SlaveInterface) - Enter password for client certificate (inline) - Password for client cert was wrong. Please reenter. (inline) - Setting client cert failed. [doesn't give reason] (inline) - "SSLInfoDialog" [mostly server cert info] (SlaveInterface) - You are about to enter secure mode. Security information/Display SSL information/Connect (inline) - You are about to leave secure mode. Security information/Continue loading/Abort (inline) - Hostname mismatch: Continue/Details/Cancel (inline) - IP address mismatch: Continue/Details/Cancel (inline) - Certificate failed authenticity check: Continue/Details/Cancel (inline) - Would you like to accept this certificate forever: Yes/No/Current sessions only (inline) */ /** @internal */ class TCPSlaveBase::TcpSlaveBasePrivate { public: TcpSlaveBasePrivate(TCPSlaveBase *qq) : q(qq) {} void setSslMetaData() { sslMetaData.insert(QStringLiteral("ssl_in_use"), QStringLiteral("TRUE")); KSslCipher cipher = socket.sessionCipher(); sslMetaData.insert(QStringLiteral("ssl_protocol_version"), socket.negotiatedSslVersionName()); QString sslCipher = cipher.encryptionMethod() + '\n'; sslCipher += cipher.authenticationMethod() + '\n'; sslCipher += cipher.keyExchangeMethod() + '\n'; sslCipher += cipher.digestMethod(); sslMetaData.insert(QStringLiteral("ssl_cipher"), sslCipher); sslMetaData.insert(QStringLiteral("ssl_cipher_name"), cipher.name()); sslMetaData.insert(QStringLiteral("ssl_cipher_used_bits"), QString::number(cipher.usedBits())); sslMetaData.insert(QStringLiteral("ssl_cipher_bits"), QString::number(cipher.supportedBits())); sslMetaData.insert(QStringLiteral("ssl_peer_ip"), ip); // try to fill in the blanks, i.e. missing certificates, and just assume that // those belong to the peer (==website or similar) certificate. for (int i = 0; i < sslErrors.count(); i++) { if (sslErrors[i].certificate().isNull()) { const QList peerCertificateChain = socket.peerCertificateChain(); sslErrors[i] = KSslError(sslErrors[i].error(), peerCertificateChain[0]); } } QString errorStr; // encode the two-dimensional numeric error list using '\n' and '\t' as outer and inner separators Q_FOREACH (const QSslCertificate &cert, socket.peerCertificateChain()) { Q_FOREACH (const KSslError &error, sslErrors) { if (error.certificate() == cert) { errorStr += QString::number(static_cast(error.error())) + '\t'; } } if (errorStr.endsWith('\t')) { errorStr.chop(1); } errorStr += '\n'; } errorStr.chop(1); sslMetaData.insert(QStringLiteral("ssl_cert_errors"), errorStr); QString peerCertChain; Q_FOREACH (const QSslCertificate &cert, socket.peerCertificateChain()) { peerCertChain.append(cert.toPem()); peerCertChain.append('\x01'); } peerCertChain.chop(1); sslMetaData.insert(QStringLiteral("ssl_peer_chain"), peerCertChain); sendSslMetaData(); } void clearSslMetaData() { sslMetaData.clear(); sslMetaData.insert(QStringLiteral("ssl_in_use"), QStringLiteral("FALSE")); sendSslMetaData(); } void sendSslMetaData() { MetaData::ConstIterator it = sslMetaData.constBegin(); for (; it != sslMetaData.constEnd(); ++it) { q->setMetaData(it.key(), it.value()); } } SslResult startTLSInternal(KTcpSocket::SslVersion sslVersion, int waitForEncryptedTimeout = -1); TCPSlaveBase *q; bool isBlocking; KTcpSocket socket; QString host; QString ip; quint16 port; QByteArray serviceName; KSSLSettings sslSettings; bool usingSSL; bool autoSSL; bool sslNoUi; // If true, we just drop the connection silently // if SSL certificate check fails in some way. QList sslErrors; MetaData sslMetaData; }; //### uh, is this a good idea?? QIODevice *TCPSlaveBase::socket() const { return &d->socket; } TCPSlaveBase::TCPSlaveBase(const QByteArray &protocol, const QByteArray &poolSocket, const QByteArray &appSocket, bool autoSSL) : SlaveBase(protocol, poolSocket, appSocket), d(new TcpSlaveBasePrivate(this)) { d->isBlocking = true; d->port = 0; d->serviceName = protocol; d->usingSSL = false; d->autoSSL = autoSSL; d->sslNoUi = false; // Limit the read buffer size to 14 MB (14*1024*1024) (based on the upload limit // in TransferJob::slotDataReq). See the docs for QAbstractSocket::setReadBufferSize // and the BR# 187876 to understand why setting this limit is necessary. d->socket.setReadBufferSize(14680064); } TCPSlaveBase::~TCPSlaveBase() { delete d; } ssize_t TCPSlaveBase::write(const char *data, ssize_t len) { ssize_t written = d->socket.write(data, len); if (written == -1) { /*qDebug() << "d->socket.write() returned -1! Socket error is" << d->socket.error() << ", Socket state is" << d->socket.state();*/ } bool success = false; if (d->isBlocking) { // Drain the tx buffer success = d->socket.waitForBytesWritten(-1); } else { // ### I don't know how to make sure that all data does get written at some point // without doing it now. There is no event loop to do it behind the scenes. // Polling in the dispatch() loop? Something timeout based? success = d->socket.waitForBytesWritten(0); } d->socket.flush(); //this is supposed to get the data on the wire faster if (d->socket.state() != KTcpSocket::ConnectedState || !success) { /*qDebug() << "Write failed, will return -1! Socket error is" << d->socket.error() << ", Socket state is" << d->socket.state() << "Return value of waitForBytesWritten() is" << success;*/ return -1; } return written; } ssize_t TCPSlaveBase::read(char *data, ssize_t len) { if (d->usingSSL && (d->socket.encryptionMode() != KTcpSocket::SslClientMode)) { d->clearSslMetaData(); //qDebug() << "lost SSL connection."; return -1; } if (!d->socket.bytesAvailable()) { const int timeout = d->isBlocking ? -1 : (readTimeout() * 1000); d->socket.waitForReadyRead(timeout); } #if 0 // Do not do this because its only benefit is to cause a nasty side effect // upstream in Qt. See BR# 260769. else if (d->socket.encryptionMode() != KTcpSocket::SslClientMode || QNetworkProxy::applicationProxy().type() == QNetworkProxy::NoProxy) { // we only do this when it doesn't trigger Qt socket bugs. When it doesn't break anything // it seems to help performance. d->socket.waitForReadyRead(0); } #endif return d->socket.read(data, len); } ssize_t TCPSlaveBase::readLine(char *data, ssize_t len) { if (d->usingSSL && (d->socket.encryptionMode() != KTcpSocket::SslClientMode)) { d->clearSslMetaData(); //qDebug() << "lost SSL connection."; return -1; } const int timeout = (d->isBlocking ? -1 : (readTimeout() * 1000)); ssize_t readTotal = 0; do { if (!d->socket.bytesAvailable()) { d->socket.waitForReadyRead(timeout); } ssize_t readStep = d->socket.readLine(&data[readTotal], len - readTotal); if (readStep == -1 || (readStep == 0 && d->socket.state() != KTcpSocket::ConnectedState)) { return -1; } readTotal += readStep; } while (readTotal == 0 || data[readTotal - 1] != '\n'); return readTotal; } bool TCPSlaveBase::connectToHost(const QString &/*protocol*/, const QString &host, quint16 port) { QString errorString; const int errCode = connectToHost(host, port, &errorString); if (errCode == 0) { return true; } error(errCode, errorString); return false; } int TCPSlaveBase::connectToHost(const QString &host, quint16 port, QString *errorString) { d->clearSslMetaData(); //We have separate connection and SSL setup phases if (errorString) { errorString->clear(); // clear prior error messages. } d->socket.setVerificationPeerName(host); // Used for ssl certificate verification (SNI) // - leaving SSL - warn before we even connect //### see if it makes sense to move this into the HTTP ioslave which is the only // user. if (metaData(QStringLiteral("main_frame_request")) == QLatin1String("TRUE") //### this looks *really* unreliable && metaData(QStringLiteral("ssl_activate_warnings")) == QLatin1String("TRUE") && metaData(QStringLiteral("ssl_was_in_use")) == QLatin1String("TRUE") && !d->autoSSL) { if (d->sslSettings.warnOnLeave()) { int result = messageBox(i18n("You are about to leave secure " "mode. Transmissions will no " "longer be encrypted.\nThis " "means that a third party could " "observe your data in transit."), WarningContinueCancel, i18n("Security Information"), i18n("C&ontinue Loading"), QString(), QStringLiteral("WarnOnLeaveSSLMode")); if (result == SlaveBase::Cancel) { if (errorString) { *errorString = host; } return ERR_USER_CANCELED; } } } /* SSL handshake is attempted in the following order: 1.) KTcpSocket::SecureProtocols 2.) KTcpSocket::TlsV1_2 3.) KTcpSocket::TlsV1_1 4.) KTcpSocket::TlsV1_0 Note that we indivially attempt connection with each TLS version because some sites don't support SSL negotiation. #275524 The version used to successfully make encrypted connection with the remote server is cached within the process to make subsequent connection requests to the same server faster. */ const int lastSslVerson = config()->readEntry("LastUsedSslVersion", static_cast(KTcpSocket::SecureProtocols)); KTcpSocket::SslVersion trySslVersion = static_cast(lastSslVerson); KTcpSocket::SslVersions alreadyTriedSslVersions = trySslVersion; const int timeout = (connectTimeout() * 1000); // 20 sec timeout value while (true) { disconnectFromHost(); //Reset some state, even if we are already disconnected d->host = host; d->socket.connectToHost(host, port); /*const bool connectOk = */d->socket.waitForConnected(timeout > -1 ? timeout : -1); /*qDebug() << "Socket: state=" << d->socket.state() << ", error=" << d->socket.error() << ", connected?" << connectOk;*/ if (d->socket.state() != KTcpSocket::ConnectedState) { if (errorString) { *errorString = host + QLatin1String(": ") + d->socket.errorString(); } switch (d->socket.error()) { case KTcpSocket::UnsupportedSocketOperationError: return ERR_UNSUPPORTED_ACTION; case KTcpSocket::RemoteHostClosedError: return ERR_CONNECTION_BROKEN; case KTcpSocket::SocketTimeoutError: return ERR_SERVER_TIMEOUT; case KTcpSocket::HostNotFoundError: return ERR_UNKNOWN_HOST; default: return ERR_CANNOT_CONNECT; } } //### check for proxyAuthenticationRequiredError d->ip = d->socket.peerAddress().toString(); d->port = d->socket.peerPort(); if (d->autoSSL) { SslResult res = d->startTLSInternal(trySslVersion, timeout); if ((res & ResultFailed) && (res & ResultFailedEarly)) { if (!(alreadyTriedSslVersions & KTcpSocket::SecureProtocols)) { trySslVersion = KTcpSocket::SecureProtocols; alreadyTriedSslVersions |= trySslVersion; continue; } if (!(alreadyTriedSslVersions & KTcpSocket::TlsV1_2)) { trySslVersion = KTcpSocket::TlsV1; alreadyTriedSslVersions |= trySslVersion; continue; } if (!(alreadyTriedSslVersions & KTcpSocket::TlsV1_1)) { trySslVersion = KTcpSocket::TlsV1; alreadyTriedSslVersions |= trySslVersion; continue; } if (!(alreadyTriedSslVersions & KTcpSocket::TlsV1_0)) { trySslVersion = KTcpSocket::TlsV1_0; alreadyTriedSslVersions |= trySslVersion; continue; } } //### SSL 2.0 is (close to) dead and it's a good thing, too. if (res & ResultFailed) { if (errorString) { *errorString = i18nc("%1 is a host name", "%1: SSL negotiation failed", host); } return ERR_CANNOT_CONNECT; } } // If the SSL handshake was done with anything protocol other than the default, // save that information so that any subsequent requests do not have to do thesame thing. if (trySslVersion != KTcpSocket::SecureProtocols && lastSslVerson == KTcpSocket::SecureProtocols) { setMetaData(QStringLiteral("{internal~currenthost}LastUsedSslVersion"), QString::number(trySslVersion)); } return 0; } Q_ASSERT(false); // Code flow never gets here but let's make the compiler happy. // More: the stack allocation of QSslSettings seems to be confusing the compiler; // in fact, any non-POD allocation does. // even a 'return 0;' directly after the allocation (so before the while(true)) // is ignored. definitely seems to be a compiler bug? - aseigo return 0; } void TCPSlaveBase::disconnectFromHost() { //qDebug(); d->host.clear(); d->ip.clear(); d->usingSSL = false; if (d->socket.state() == KTcpSocket::UnconnectedState) { // discard incoming data - the remote host might have disconnected us in the meantime // but the visible effect of disconnectFromHost() should stay the same. d->socket.close(); return; } //### maybe save a session for reuse on SSL shutdown if and when QSslSocket // does that. QCA::TLS can do it apparently but that is not enough if // we want to present that as KDE API. Not a big loss in any case. d->socket.disconnectFromHost(); if (d->socket.state() != KTcpSocket::UnconnectedState) { d->socket.waitForDisconnected(-1); // wait for unsent data to be sent } d->socket.close(); //whatever that means on a socket } bool TCPSlaveBase::isAutoSsl() const { return d->autoSSL; } bool TCPSlaveBase::isUsingSsl() const { return d->usingSSL; } quint16 TCPSlaveBase::port() const { return d->port; } bool TCPSlaveBase::atEnd() const { return d->socket.atEnd(); } bool TCPSlaveBase::startSsl() { if (d->usingSSL) { return false; } return d->startTLSInternal(KTcpSocket::SecureProtocols) & ResultOk; } TCPSlaveBase::SslResult TCPSlaveBase::TcpSlaveBasePrivate::startTLSInternal(KTcpSocket::SslVersion version, int waitForEncryptedTimeout) { q->selectClientCertificate(); //setMetaData("ssl_session_id", d->kssl->session()->toString()); //### we don't support session reuse for now... usingSSL = true; // Set the SSL version to use... socket.setAdvertisedSslVersion(version); /* Usually ignoreSslErrors() would be called in the slot invoked by the sslErrors() signal but that would mess up the flow of control. We will check for errors anyway to decide if we want to continue connecting. Otherwise ignoreSslErrors() before connecting would be very insecure. */ socket.ignoreSslErrors(); socket.startClientEncryption(); const bool encryptionStarted = socket.waitForEncrypted(waitForEncryptedTimeout); //Set metadata, among other things for the "SSL Details" dialog KSslCipher cipher = socket.sessionCipher(); if (!encryptionStarted || socket.encryptionMode() != KTcpSocket::SslClientMode || cipher.isNull() || cipher.usedBits() == 0 || socket.peerCertificateChain().isEmpty()) { usingSSL = false; clearSslMetaData(); /*qDebug() << "Initial SSL handshake failed. encryptionStarted is" << encryptionStarted << ", cipher.isNull() is" << cipher.isNull() << ", cipher.usedBits() is" << cipher.usedBits() << ", length of certificate chain is" << socket.peerCertificateChain().count() << ", the socket says:" << socket.errorString() << "and the list of SSL errors contains" << socket.sslErrors().count() << "items.";*/ /*Q_FOREACH(const KSslError& sslError, socket.sslErrors()) { qDebug() << "SSL ERROR: (" << sslError.error() << ")" << sslError.errorString(); }*/ return ResultFailed | ResultFailedEarly; } /*qDebug() << "Cipher info - " << " advertised SSL protocol version" << socket.advertisedSslVersion() << " negotiated SSL protocol version" << socket.negotiatedSslVersion() << " authenticationMethod:" << cipher.authenticationMethod() << " encryptionMethod:" << cipher.encryptionMethod() << " keyExchangeMethod:" << cipher.keyExchangeMethod() << " name:" << cipher.name() << " supportedBits:" << cipher.supportedBits() << " usedBits:" << cipher.usedBits();*/ sslErrors = socket.sslErrors(); // TODO: review / rewrite / remove the comment // The app side needs the metadata now for the SSL error dialog (if any) but // the same metadata will be needed later, too. When "later" arrives the slave // may actually be connected to a different application that doesn't know // the metadata the slave sent to the previous application. // The quite important SSL indicator icon in Konqi's URL bar relies on metadata // from here, for example. And Konqi will be the second application to connect // to the slave. // Therefore we choose to have our metadata and send it, too :) setSslMetaData(); q->sendAndKeepMetaData(); SslResult rc = q->verifyServerCertificate(); if (rc & ResultFailed) { usingSSL = false; clearSslMetaData(); //qDebug() << "server certificate verification failed."; socket.disconnectFromHost(); //Make the connection fail (cf. ignoreSslErrors()) return ResultFailed; } else if (rc & ResultOverridden) { //qDebug() << "server certificate verification failed but continuing at user's request."; } //"warn" when starting SSL/TLS if (q->metaData(QStringLiteral("ssl_activate_warnings")) == QLatin1String("TRUE") && q->metaData(QStringLiteral("ssl_was_in_use")) == QLatin1String("FALSE") && sslSettings.warnOnEnter()) { int msgResult = q->messageBox(i18n("You are about to enter secure mode. " "All transmissions will be encrypted " "unless otherwise noted.\nThis means " "that no third party will be able to " "easily observe your data in transit."), WarningYesNo, i18n("Security Information"), i18n("Display SSL &Information"), i18n("C&onnect"), QStringLiteral("WarnOnEnterSSLMode")); if (msgResult == SlaveBase::Yes) { q->messageBox(SSLMessageBox /*==the SSL info dialog*/, host); } } return rc; } void TCPSlaveBase::selectClientCertificate() { #if 0 //hehe QString certname; // the cert to use this session bool send = false, prompt = false, save = false, forcePrompt = false; KSSLCertificateHome::KSSLAuthAction aa; setMetaData("ssl_using_client_cert", "FALSE"); // we change this if needed if (metaData("ssl_no_client_cert") == "TRUE") { return; } forcePrompt = (metaData("ssl_force_cert_prompt") == "TRUE"); // Delete the old cert since we're certainly done with it now if (d->pkcs) { delete d->pkcs; d->pkcs = NULL; } if (!d->kssl) { return; } // Look for a general certificate if (!forcePrompt) { certname = KSSLCertificateHome::getDefaultCertificateName(&aa); switch (aa) { case KSSLCertificateHome::AuthSend: send = true; prompt = false; break; case KSSLCertificateHome::AuthDont: send = false; prompt = false; certname.clear(); break; case KSSLCertificateHome::AuthPrompt: send = false; prompt = true; break; default: break; } } // Look for a certificate on a per-host basis as an override QString tmpcn = KSSLCertificateHome::getDefaultCertificateName(d->host, &aa); if (aa != KSSLCertificateHome::AuthNone) { // we must override switch (aa) { case KSSLCertificateHome::AuthSend: send = true; prompt = false; certname = tmpcn; break; case KSSLCertificateHome::AuthDont: send = false; prompt = false; certname.clear(); break; case KSSLCertificateHome::AuthPrompt: send = false; prompt = true; certname = tmpcn; break; default: break; } } // Finally, we allow the application to override anything. if (hasMetaData("ssl_demand_certificate")) { certname = metaData("ssl_demand_certificate"); if (!certname.isEmpty()) { forcePrompt = false; prompt = false; send = true; } } if (certname.isEmpty() && !prompt && !forcePrompt) { return; } // Ok, we're supposed to prompt the user.... if (prompt || forcePrompt) { QStringList certs = KSSLCertificateHome::getCertificateList(); QStringList::const_iterator it = certs.begin(); while (it != certs.end()) { KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(*it); if (pkcs && (!pkcs->getCertificate() || !pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())) { it = certs.erase(it); } else { ++it; } delete pkcs; } if (certs.isEmpty()) { return; // we had nothing else, and prompt failed } QDBusConnectionInterface *bus = QDBusConnection::sessionBus().interface(); if (!bus->isServiceRegistered("org.kde.kio.uiserver")) { bus->startService("org.kde.kuiserver"); } QDBusInterface uis("org.kde.kio.uiserver", "/UIServer", "org.kde.KIO.UIServer"); QDBusMessage retVal = uis.call("showSSLCertDialog", d->host, certs, metaData("window-id").toLongLong()); if (retVal.type() == QDBusMessage::ReplyMessage) { if (retVal.arguments().at(0).toBool()) { send = retVal.arguments().at(1).toBool(); save = retVal.arguments().at(2).toBool(); certname = retVal.arguments().at(3).toString(); } } } // The user may have said to not send the certificate, // but to save the choice if (!send) { if (save) { KSSLCertificateHome::setDefaultCertificate(certname, d->host, false, false); } return; } // We're almost committed. If we can read the cert, we'll send it now. KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(certname); if (!pkcs && KSSLCertificateHome::hasCertificateByName(certname)) { // We need the password KIO::AuthInfo ai; bool first = true; do { ai.prompt = i18n("Enter the certificate password:"); ai.caption = i18n("SSL Certificate Password"); ai.url.setScheme("kssl"); ai.url.setHost(certname); ai.username = certname; ai.keepPassword = true; bool showprompt; if (first) { showprompt = !checkCachedAuthentication(ai); } else { showprompt = true; } if (showprompt) { if (!openPasswordDialog(ai, first ? QString() : i18n("Unable to open the certificate. Try a new password?"))) { break; } } first = false; pkcs = KSSLCertificateHome::getCertificateByName(certname, ai.password); } while (!pkcs); } // If we could open the certificate, let's send it if (pkcs) { if (!d->kssl->setClientCertificate(pkcs)) { messageBox(Information, i18n("The procedure to set the " "client certificate for the session " "failed."), i18n("SSL")); delete pkcs; // we don't need this anymore pkcs = 0L; } else { //qDebug() << "Client SSL certificate is being used."; setMetaData("ssl_using_client_cert", "TRUE"); if (save) { KSSLCertificateHome::setDefaultCertificate(certname, d->host, true, false); } } d->pkcs = pkcs; } #endif } TCPSlaveBase::SslResult TCPSlaveBase::verifyServerCertificate() { d->sslNoUi = hasMetaData(QStringLiteral("ssl_no_ui")) && (metaData(QStringLiteral("ssl_no_ui")) != QLatin1String("FALSE")); if (d->sslErrors.isEmpty()) { return ResultOk; } else if (d->sslNoUi) { return ResultFailed; } QList fatalErrors = KSslCertificateManager::nonIgnorableErrors(d->sslErrors); if (!fatalErrors.isEmpty()) { //TODO message "sorry, fatal error, you can't override it" return ResultFailed; } QList peerCertificationChain = d->socket.peerCertificateChain(); KSslCertificateManager *const cm = KSslCertificateManager::self(); KSslCertificateRule rule = cm->rule(peerCertificationChain.first(), d->host); // remove previously seen and acknowledged errors QList remainingErrors = rule.filterErrors(d->sslErrors); if (remainingErrors.isEmpty()) { //qDebug() << "Error list empty after removing errors to be ignored. Continuing."; return ResultOk | ResultOverridden; } //### We don't ask to permanently reject the certificate QString message = i18n("The server failed the authenticity check (%1).\n\n", d->host); Q_FOREACH (const KSslError &err, d->sslErrors) { message.append(err.errorString()); message.append('\n'); } message = message.trimmed(); int msgResult; QDateTime ruleExpiry = QDateTime::currentDateTime(); do { msgResult = messageBox(WarningYesNoCancel, message, i18n("Server Authentication"), i18n("&Details"), i18n("Co&ntinue")); switch (msgResult) { case SlaveBase::Yes: //Details was chosen- show the certificate and error details messageBox(SSLMessageBox /*the SSL info dialog*/, d->host); break; case SlaveBase::No: { //fall through on SlaveBase::No const int result = messageBox(WarningYesNoCancel, i18n("Would you like to accept this " "certificate forever without " "being prompted?"), i18n("Server Authentication"), i18n("&Forever"), i18n("&Current Session only")); if (result == SlaveBase::Yes) { //accept forever ("for a very long time") ruleExpiry = ruleExpiry.addYears(1000); } else if (result == SlaveBase::No) { //accept "for a short time", half an hour. ruleExpiry = ruleExpiry.addSecs(30*60); } else { msgResult = SlaveBase::Yes; } break; } case SlaveBase::Cancel: return ResultFailed; default: qCWarning(KIO_CORE) << "Unexpected MessageBox response received:" << msgResult; return ResultFailed; } } while (msgResult == SlaveBase::Yes); //TODO special cases for wildcard domain name in the certificate! //rule = KSslCertificateRule(d->socket.peerCertificateChain().first(), whatever); rule.setExpiryDateTime(ruleExpiry); rule.setIgnoredErrors(d->sslErrors); cm->setRule(rule); return ResultOk | ResultOverridden; -#if 0 //### need to to do something like the old code about the main and subframe stuff +#if 0 //### need to do something like the old code about the main and subframe stuff //qDebug() << "SSL HTTP frame the parent? " << metaData("main_frame_request"); if (!hasMetaData("main_frame_request") || metaData("main_frame_request") == "TRUE") { // Since we're the parent, we need to teach the child. setMetaData("ssl_parent_ip", d->ip); setMetaData("ssl_parent_cert", pc.toString()); // - Read from cache and see if there is a policy for this KSSLCertificateCache::KSSLCertificatePolicy cp = d->certCache->getPolicyByCertificate(pc); // - validation code if (ksv != KSSLCertificate::Ok) { if (d->sslNoUi) { return -1; } if (cp == KSSLCertificateCache::Unknown || cp == KSSLCertificateCache::Ambiguous) { cp = KSSLCertificateCache::Prompt; } else { // A policy was already set so let's honor that. permacache = d->certCache->isPermanent(pc); } if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept) { cp = KSSLCertificateCache::Prompt; // ksv = KSSLCertificate::Ok; } ////// SNIP SNIP ////////// // - cache the results d->certCache->addCertificate(pc, cp, permacache); if (doAddHost) { d->certCache->addHost(pc, d->host); } } else { // Child frame // - Read from cache and see if there is a policy for this KSSLCertificateCache::KSSLCertificatePolicy cp = d->certCache->getPolicyByCertificate(pc); isChild = true; // Check the cert and IP to make sure they're the same // as the parent frame bool certAndIPTheSame = (d->ip == metaData("ssl_parent_ip") && pc.toString() == metaData("ssl_parent_cert")); if (ksv == KSSLCertificate::Ok) { if (certAndIPTheSame) { // success rc = 1; setMetaData("ssl_action", "accept"); } else { /* if (d->sslNoUi) { return -1; } result = messageBox(WarningYesNo, i18n("The certificate is valid but does not appear to have been assigned to this server. Do you wish to continue loading?"), i18n("Server Authentication")); if (result == SlaveBase::Yes) { // success rc = 1; setMetaData("ssl_action", "accept"); } else { // fail rc = -1; setMetaData("ssl_action", "reject"); } */ setMetaData("ssl_action", "accept"); rc = 1; // Let's accept this now. It's bad, but at least the user // will see potential attacks in KDE3 with the pseudo-lock // icon on the toolbar, and can investigate with the RMB } } else { if (d->sslNoUi) { return -1; } if (cp == KSSLCertificateCache::Accept) { if (certAndIPTheSame) { // success rc = 1; setMetaData("ssl_action", "accept"); } else { // fail result = messageBox(WarningYesNo, i18n("You have indicated that you wish to accept this certificate, but it is not issued to the server who is presenting it. Do you wish to continue loading?"), i18n("Server Authentication")); if (result == SlaveBase::Yes) { rc = 1; setMetaData("ssl_action", "accept"); d->certCache->addHost(pc, d->host); } else { rc = -1; setMetaData("ssl_action", "reject"); } } } else if (cp == KSSLCertificateCache::Reject) { // fail messageBox(Information, i18n("SSL certificate is being rejected as requested. You can disable this in the KDE System Settings."), i18n("Server Authentication")); rc = -1; setMetaData("ssl_action", "reject"); } else { //////// SNIP SNIP ////////// return rc; } } } } #endif //#if 0 } bool TCPSlaveBase::isConnected() const { //QSslSocket::isValid() and therefore KTcpSocket::isValid() are shady... return d->socket.state() == KTcpSocket::ConnectedState; } bool TCPSlaveBase::waitForResponse(int t) { if (d->socket.bytesAvailable()) { return true; } return d->socket.waitForReadyRead(t * 1000); } void TCPSlaveBase::setBlocking(bool b) { if (!b) { qCWarning(KIO_CORE) << "Caller requested non-blocking mode, but that doesn't work"; return; } d->isBlocking = b; } void TCPSlaveBase::virtual_hook(int id, void *data) { if (id == SlaveBase::AppConnectionMade) { d->sendSslMetaData(); } else { SlaveBase::virtual_hook(id, data); } } diff --git a/src/core/transferjob.h b/src/core/transferjob.h index a443538d..9e607393 100644 --- a/src/core/transferjob.h +++ b/src/core/transferjob.h @@ -1,319 +1,319 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Stephan Kulow 2000-2013 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIO_TRANSFERJOB_H #define KIO_TRANSFERJOB_H #include "simplejob.h" namespace KIO { class TransferJobPrivate; /** * The transfer job pumps data into and/or out of a Slave. * Data is sent to the slave on request of the slave ( dataReq). * If data coming from the slave can not be handled, the * reading of data from the slave should be suspended. */ class KIOCORE_EXPORT TransferJob : public SimpleJob { Q_OBJECT public: ~TransferJob(); /** * Sets the modification time of the file to be created (by KIO::put) * Note that some kioslaves might ignore this. */ void setModificationTime(const QDateTime &mtime); /** * Checks whether we got an error page. This currently only happens * with HTTP urls. Call this from your slot connected to result(). * * @return true if we got an (HTML) error page from the server * instead of what we asked for. */ bool isErrorPage() const; /** * Enable the async data mode. * When async data is enabled, data should be provided to the job by * calling sendAsyncData() instead of returning data in the * dataReq() signal. */ void setAsyncDataEnabled(bool enabled); /** * Provide data to the job when async data is enabled. * Should be called exactly once after receiving a dataReq signal * Sending an empty block indicates end of data. */ void sendAsyncData(const QByteArray &data); /** * When enabled, the job reports the amount of data that has been sent, - * instead of the amount of data that that has been received. + * instead of the amount of data that has been received. * @see slotProcessedSize * @see slotSpeed * @deprecated since 4.2.1, this is unnecessary (it is always false for * KIO::get and true for KIO::put) */ #ifndef KIOCORE_NO_DEPRECATED KIOCORE_DEPRECATED void setReportDataSent(bool enabled); #endif /** * Returns whether the job reports the amount of data that has been * sent (true), or whether the job reports the amount of data that * has been received (false) * @deprecated since 4.2.1, this is unnecessary (it is always false for * KIO::get and true for KIO::put) */ #ifndef KIOCORE_NO_DEPRECATED KIOCORE_DEPRECATED bool reportDataSent() const; #endif /** * Call this in the slot connected to result, * and only after making sure no error happened. * @return the mimetype of the URL */ QString mimetype() const; /** * After the job has finished, it will return the final url in case a redirection * has happened. * @return the final url that can be empty in case no redirection has happened. * @since 5.0 */ QUrl redirectUrl() const; /** * Set the total size of data that we are going to send * in a put job. Helps getting proper progress information. * @since 4.2.1 */ void setTotalSize(KIO::filesize_t bytes); protected: /** * Called when m_subJob finishes. * @param job the job that finished */ void slotResult(KJob *job) Q_DECL_OVERRIDE; /** * Reimplemented for internal reasons */ bool doResume() Q_DECL_OVERRIDE; Q_SIGNALS: /** * Data from the slave has arrived. * @param job the job that emitted this signal * @param data data received from the slave. * * End of data (EOD) has been reached if data.size() == 0, however, you * should not be certain of data.size() == 0 ever happening (e.g. in case * of an error), so you should rely on result() instead. */ void data(KIO::Job *job, const QByteArray &data); /** * Request for data. * Please note, that you shouldn't put too large chunks * of data in it as this requires copies within the frame * work, so you should rather split the data you want * to pass here in reasonable chunks (about 1MB maximum) * * @param job the job that emitted this signal * @param data buffer to fill with data to send to the * slave. An empty buffer indicates end of data. (EOD) */ void dataReq(KIO::Job *job, QByteArray &data); /** * Signals a redirection. * Use to update the URL shown to the user. * The redirection itself is handled internally. * @param job the job that emitted this signal * @param url the new URL */ void redirection(KIO::Job *job, const QUrl &url); /** * Signals a permanent redirection. * The redirection itself is handled internally. * @param job the job that emitted this signal * @param fromUrl the original URL * @param toUrl the new URL */ void permanentRedirection(KIO::Job *job, const QUrl &fromUrl, const QUrl &toUrl); /** * Mimetype determined. * @param job the job that emitted this signal * @param type the mime type */ void mimetype(KIO::Job *job, const QString &type); /** * @internal * Emitted if the "put" job found an existing partial file * (in which case offset is the size of that file) * and emitted by the "get" job if it supports resuming to * the given offset - in this case @p offset is unused) */ void canResume(KIO::Job *job, KIO::filesize_t offset); protected Q_SLOTS: virtual void slotRedirection(const QUrl &url); void slotFinished() Q_DECL_OVERRIDE; virtual void slotData(const QByteArray &data); virtual void slotDataReq(); virtual void slotMimetype(const QString &mimetype); void slotMetaData(const KIO::MetaData &_metaData) Q_DECL_OVERRIDE; protected: TransferJob(TransferJobPrivate &dd); private: Q_PRIVATE_SLOT(d_func(), void slotErrorPage()) Q_PRIVATE_SLOT(d_func(), void slotCanResume(KIO::filesize_t offset)) Q_PRIVATE_SLOT(d_func(), void slotPostRedirection()) Q_PRIVATE_SLOT(d_func(), void slotNeedSubUrlData()) Q_PRIVATE_SLOT(d_func(), void slotSubUrlData(KIO::Job *, const QByteArray &)) Q_PRIVATE_SLOT(d_func(), void slotDataReqFromDevice()) Q_PRIVATE_SLOT(d_func(), void slotIODeviceClosed()) Q_DECLARE_PRIVATE(TransferJob) // A FileCopyJob may control one or more TransferJobs friend class FileCopyJob; friend class FileCopyJobPrivate; }; /** * Get (means: read). * This is the job to use in order to "download" a file into memory. * The slave emits the data through the data() signal. * * Special case: if you want to determine the mimetype of the file first, * and then read it with the appropriate component, you can still use * a KIO::get() directly. When that job emits the mimeType signal, (which is * guaranteed to happen before it emits any data), put the job on hold: * * @code * job->putOnHold(); * KIO::Scheduler::publishSlaveOnHold(); * @endcode * * and forget about the job. The next time someone does a KIO::get() on the * same URL (even in another process) this job will be resumed. This saves KIO * from doing two requests to the server. * * @param url the URL of the file * @param reload Reload to reload the file, NoReload if it can be taken from the cache * @param flags Can be HideProgressInfo here * @return the job handling the operation. */ KIOCORE_EXPORT TransferJob *get(const QUrl &url, LoadType reload = NoReload, JobFlags flags = DefaultFlags); /** * Put (means: write) * * @param url Where to write data. * @param permissions May be -1. In this case no special permission mode is set. * @param flags Can be HideProgressInfo, Overwrite and Resume here. WARNING: * Setting Resume means that the data will be appended to @p dest if @p dest exists. * @return the job handling the operation. * @see multi_get() */ KIOCORE_EXPORT TransferJob *put(const QUrl &url, int permissions, JobFlags flags = DefaultFlags); /** * HTTP POST (for form data). * * Example: * \code * job = KIO::http_post( url, postData, KIO::HideProgressInfo ); * job->addMetaData("content-type", contentType ); * job->addMetaData("referrer", referrerURL); * \endcode * * @p postData is the data that you want to send and * @p contentType is the complete HTTP header line that * specifies the content's MIME type, for example * "Content-Type: text/xml". * * You MUST specify content-type! * * Often @p contentType is * "Content-Type: application/x-www-form-urlencoded" and * the @p postData is then an ASCII string (without null-termination!) * with characters like space, linefeed and percent escaped like %20, * %0A and %25. * * @param url Where to write the data. * @param postData Encoded data to post. * @param flags Can be HideProgressInfo here * @return the job handling the operation. */ KIOCORE_EXPORT TransferJob *http_post(const QUrl &url, const QByteArray &postData, JobFlags flags = DefaultFlags); /** * HTTP POST. * * This function, unlike the one that accepts a QByteArray, accepts an IO device * from which to read the encoded data to be posted to the server in order to * to avoid holding the content of very large post requests, e.g. multimedia file * uploads, in memory. * * @param url Where to write the data. * @param device the device to read from * @param size Size of the encoded post data. * @param flags Can be HideProgressInfo here * @return the job handling the operation. * * @since 4.7 */ KIOCORE_EXPORT TransferJob *http_post(const QUrl &url, QIODevice *device, qint64 size = -1, JobFlags flags = DefaultFlags); /** * HTTP DELETE. * * Though this function servers the same purpose as KIO::file_delete, unlike * file_delete it accommodates HTTP sepecific actions such as redirections. * * @param url url resource to delete. * @param flags Can be HideProgressInfo here * @return the job handling the operation. * * @since 4.7.3 */ KIOCORE_EXPORT TransferJob *http_delete(const QUrl &url, JobFlags flags = DefaultFlags); } #endif diff --git a/src/filewidgets/kurlnavigatorbuttonbase_p.h b/src/filewidgets/kurlnavigatorbuttonbase_p.h index 69145da3..5e88e88a 100644 --- a/src/filewidgets/kurlnavigatorbuttonbase_p.h +++ b/src/filewidgets/kurlnavigatorbuttonbase_p.h @@ -1,91 +1,91 @@ /***************************************************************************** * Copyright (C) 2006-2010 by Peter Penz * * Copyright (C) 2006 by Aaron J. Seigo * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public License * * along with this library; see the file COPYING.LIB. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * *****************************************************************************/ #ifndef KURLNAVIGATORBUTTONBASE_P_H #define KURLNAVIGATORBUTTONBASE_P_H #include #include class QUrl; class QEvent; namespace KDEPrivate { /** * @brief Base class for buttons of the URL navigator. * - * Buttons of the URL navigator offer an an active/inactive + * Buttons of the URL navigator offer an active/inactive * state and custom display hints. */ class KUrlNavigatorButtonBase : public QPushButton { Q_OBJECT public: explicit KUrlNavigatorButtonBase(QWidget *parent); virtual ~KUrlNavigatorButtonBase(); /** * When having several URL navigator instances, it is important * to provide a visual difference to indicate which URL navigator * is active (usecase: split view in Dolphin). The activation state * is independent from the focus or hover state. * Per default the URL navigator button is marked as active. */ void setActive(bool active); bool isActive() const; protected: enum DisplayHint { EnteredHint = 1, DraggedHint = 2, PopupActiveHint = 4 }; enum { BorderWidth = 2 }; void setDisplayHintEnabled(DisplayHint hint, bool enable); bool isDisplayHintEnabled(DisplayHint hint) const; void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE; void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE; void enterEvent(QEvent *event) Q_DECL_OVERRIDE; void leaveEvent(QEvent *event) Q_DECL_OVERRIDE; void drawHoverBackground(QPainter *painter); /** Returns the foreground color by respecting the current display hint. */ QColor foregroundColor() const; private Q_SLOTS: /** Invokes setActive(true). */ void activate(); private: bool m_active; int m_displayHint; }; } // namespace KDEPrivate #endif diff --git a/src/ioslaves/http/shoutcast-icecast.txt b/src/ioslaves/http/shoutcast-icecast.txt index 5207bb71..c8e56540 100644 --- a/src/ioslaves/http/shoutcast-icecast.txt +++ b/src/ioslaves/http/shoutcast-icecast.txt @@ -1,605 +1,605 @@ Audio and Apache HTTPD ApacheCon 2001 Santa Clara, US April 6th, 2001 Sander van Zoest Covalent Technologies, Inc. Latest version can be found at: Introduction: About this paper: Contents: 1. Why serve Audio on the Net? This is almost like asking, why are you reading this? it might be because of the excitement caused by the new media that has recently crazed upon the internet. People are looking to bring their lifes onto the net, one of the things that brings that closer to a reality is the ability to hear live broadcasts of the worlds news, favorite sport; hear music and to teleconference with others. Sometimes it is simply to enhance the mood to a web site or to provide audio feedback of actions performed by the visitor of the web site. 2. What makes delivering audio so different? The biggest reason to what makes audio different than traditional web media such as graphics, text and HTML is the fact that timing is very important. This caused by the significant increase in size of the media and the different quality levels that exist. There really are two kinds of goals behind audio streams. In one case there is a need for immediate response the moment playback is requested and this can sacrifice quality. While in the other case quality and a non-interrupted stream are much more important. This sort of timing is not really required of any other media, with the exception of video. In the case of HTML and images the files sizes are usually a lot smaller which causes the objects to load much quicker and usually are not very useful without having the entire file. In audio the middle of a stream can have useful information and still set a particular mood. 3. Different ways of delivery Audio on the Net. Embedding audio in your Web Page This used to be a lot more common in the past. Just like embedding an image in a web page, it is possible to add a sound clip or score to the web page. The linked in audio files are usually short and of low quality to avoid a long delay for downloading the rest of the web page and the audio format needs to be supported by the browser natively or with a browser plug-in to avoid annoying the visitor. This can be accomplished using the HTML 4.0 [HTML4] object element which works similar to how to specify an applet with the object element. In the past this could also be accomplished using the embed and bgsound browser specific additions to HTML. example: Each param element is specific to each browser. Please check with each browser for specific information in regards to what param elements are available. In this method of delivering audio the audio file is served up via the web server. When using an Apache HTTPD server make sure that the appropriate mime type is configured for the audio file and that the audio file is named and referenced by the appropriate extension. Although the current HTML 4.01 [HTML4] says to use the object element many browsers out on the market today still look for the embed element. - Below find a little snipbit that will work work in many browsers. + Below find a little snipbit that will work in many browsers. Your browser does not support embedded WAV files. With the increasing installation base of the Flash browser plug-in by Macromedia most developers that are looking to provide this kind of functionality to a web page are creating flash elements that have their own way of adding audio that is discussed in Flash specific documents. Downloading via HTTP Using this method the visitor to the website will have to download the entire audio file and save it to the hard drive before it can be listened to. (1) This is very popular with people that want to listen to high quality streams of audio and have a below ISDN connection to the internet. In some cases where the demand for a stream is high or the internet is congested downloading the content even for high bandwidth users can be affective and useful. One of the advantages of downloading audio to the local computer hard drive is that it can be played back (once downloaded) any time as long as the audio file is accessable from the computer. There are a lot of sites on the internet that provide this functionality for music and other audio files. It is also one of the easiest ways to delivery high quality audio to visitors. (1) Microsoft Windows Media Player in conjunction with the Microsoft Internet Explorer Browser will automatically start playing the audio stream after a sufficient amount of the file has been downloaded. This can be accomplished because of the tight integration of the Browser and Media Player. With most audio players you can listen to a file being downloaded, but you will have to envoke the action manually. . On-Demand streaming via HTTP The real difference between downloading and on-demand streaming is that in on-demand streaming the audio starts playing before the entire audio file has been downloaded. This is accomplished by a hand of off the browser to the audio player via an intermediate file format that has been configured by the browser to be handled by the audio player. Look in a further section entitled "Linking to Audio via Apache HTTPD" below for more information about the different intermediate file formats. This type of streaming is very popular among the open source crowd and is the most widely implemented using the MP3 file format. Apache, Shoutcast [SHOUTCAST] and Icecast [ICECAST] are the most common software components used to provide on-demand streaming via HTTP. Both Icecast and Shoutcast are not fully HTTP compliant, but Icecast is becoming closer. For more information about the Shoutcast and Icecast differences see the section below. Sites like Live365.com and MP3.com are huge sites that rely on this method of delivery of audio. . On-Demand Streaming via RTSP/RTP RTSP/RTP is a new set of streaming protocols that is getting more backing and becoming more popular by the second. The specification was developed by the Internet Engineering Task Force Working Groups AVT [IETFAVT] and MMUSIC [IETFMMUSIC]. RTP the Realtime Transfer Protocol has been around longer than RTSP and originally came out of the work towards a better teleconferencing, mbone, type system. RTSP is the Real-Time Streaming Protocol that is used as a control protocol and acts similarily to HTTP except that it maintains state and is bi-directional. Currently the latest Real Networks Streaming Servers support RTSP and RTP and Real Networks own proprietary transfer protocol RDT. Apple's Darwin Streaming server is also RTSP/RTP compliant. The RTSP/RTP protocol suite is very powerful and flexable in regards to your streaming needs. It has the ability to support "server-push" style stream redirects and has the ability to throttle streams to ensure the stream can sustain the limited bandwidth over the network. For On-Demand streams the RTP protocol would usually stream over TCP and have a second TCP connection open for RTSP. Because of the rich features provided by the protocol suite, it is not very well suited to allow people to download the stream and therefore the download via HTTP method might still be preferred by some. . Live Broadcast Streaming via RTSP/RTP In the case of a live broadcast streaming RTSP/RTP shines. RTP allowing for UDP datagrams to be transmitted to clients allows for fast immediate delivery of content with the sacrifice of reliability. The RTP stream can be send over IP Multicast to minimize bandwidth on the network. Many Content Delivery Networks (CDNs) are starting to provide support for RTSP/RTP proxies that should provide a better quality streaming environment on the internet. Much work is also being done in the RTP space to provide transfers over telecommunication networks such as cellular phones. Although not directly related, per se, it does provide a positive feeling knowing that all the audio related transfer groups seem to be working towards a common standard such as RTP. . On-Demand or Live Broadcast streaming via MMS. This is the Microsoft Windows Media Technologies Streaming protocol. It is only supported by Microsoft Windows Media Player and currently only works on Microsoft Windows. 5. Configuring Mime Types One of the most hardest things in serving audio has been the wide variety of audio codecs and mime types available. The battle of mime types on the audio player side of things isn't over, but it seems to be a little more controlled. On the server side of things provide the appropriate mime type for the particular audio streams and/or files that are being served to the audio players. Although some clients and operating systems handle files fully based on the file extension. The mime type [RFC2045] is more specific and more defined. The registered mime types are maintained by IANA [IANA]. On their site they have a list of all the registered mime types and their name space. If you are planning on using a mime type that isn't registered by IANA then signal this in the name space by adding a "x-" before the subtype. Because this was not done very often in the audio space, there was a lot of confusion to what the real mime type should be. For example the MPEG 1.0 Layer 3 Audio (MP3) [ORAMP3BOOK] mime type was not specified for the longest time. Because of this the mime type was audio/x-mpeg. Although none of the audio players understood audio/x-mpeg, but understood audio/mpeg it was not a technically correct mime type. Later audio players recognized this and started using the audio/x-mpeg mime type. Which in the end caused a lot of hassles with clients needing to be configured differently depending on the website and client that was used. Last november we thanked Martin Nilsson of the ID3 tagging project for registering audo/mpeg with IANA. [RFC3003] Correct configuration of Mime Types is very important. Apache HTTPD ships with a fairly up to date copy of the mime.types file, so most of the default ones (including audio/mpeg) are there. But in case you run into some that are not defined use the mod_mime directives such as AddType to fix this. Examples: AddType audio/x-mpegurl .m3u AddType audio/x-scpls .pls AddType application/x-ogg .ogg 6. Common Audio File Formats There are many audio formats and metadata formats that exist. Many of them do not have registered mime types and are hardly documented. This section is an attempt at providing the most accurate mime type information for each format with a rough description of what the files are used for. . Real Audio Real Networks Proprietary audio format and meta formats. This is one of the more common streaming audio formats today. It comes in several sub flavors such as Real 5.0, Real G2 and Real 8.0 etc. The file size varies depending on the bitrates and what combination of bitrates are contained within the single file. The following mime types are used audio/x-pn-realaudio .ra, .ram, .rm audio/x-pn-realaudio-plugin .rpm application/x-pn-realmedia . MPEG 1.0 Layer 3 Audio (MP3) This is currently one of the most popular downloaded audio formats that was originally developed by the Motion Pictures Experts Group and has patents by the Fraunhofer IIS Institute and Thompson Multimedia. [ORAMP3BOOK] The file is a lossy compression that at a bitrate of 128kbps reduces the file size to roughly a MB/minute. The mime type is audio/mpeg with the extension of .mp3 [RFC3003] . Windows Media Audio Originally known as MS Audio was developed by Microsoft as the MP3 killer. Still relatively a new format but heavily marketed by Microsoft and becoming more popular by the minute. It is a successor to the Microsoft Audio Streaming Format (ASF). . WAV Windows Audio Format is a pretty semi-complicated encapsulating format that in the most common case is PCM with a WAV header up front. It has the mime type audio/x-wav with the extension .wav. . Vorbis Ogg Vorbis [VORBIS] is still a relatively new format brought to life by CD Paranoia author Christopher Montgomery; known to the world as Monty. It is an open source audio format free of patents and gotchas. It is a codec/file format that is roughly as good as the MP3 format, if not much better. The mime type for Ogg Vorbis is application/x-ogg with the extension of .ogg. . MIDI The MIDI standard and file format [MIDISPEC] have been used by Musicians for a long time. It is a great format to add music to a website without the long download times and needing special players or plug-ins. The mime type is audio/x-midi and the extension is .mid . Shockwave Flash (ADPCM/MP3) [FLASH4AUDIO] Macromedia Flash [FLASH4AUDIO] uses its own internal audio format that is often used on Flash websites. It is based on Adaptive Differential Pulse Code Modulation (ADPCM) and the MP3 file format. Because it is usually used from within Flash it usually isn't served up seperatedly but it's extension is .swf There are many many many more audio codecs and file formats that exist. I have listed a few that won't be discussed but should be kept in mind. Formats such as PCM/Raw Audio (audio/basic), MOD, MIDI (audio/x-midi), QDesign (used by Quicktime), Beatnik, Sun's AU, Apple/SGI's AIFF, AAC by the MPEG Group, Liquid Audio and AT&T's a2b (AAC derivatives), Dolby AC-3, Yamaha's TwinVQ (originally by Nippon Telephone and Telegraph) and MPEG-4 audio. 7. Linking to Audio via Apache HTTPD There are many different ways to link to audio from the Apache HTTPD web server. It seems as if every codec has their own metafile format. The metafile format is provided to allow the browser to hand off the job of requesting the audio file to the audio player, because it is more familiar with the file format and how to handle streaming or how to actually connect to the audio server then the web browser is. This section will discuss the more common methods to provide streaming links to provide that gateway from the web to the audio world. Probably the one that is the most recognized file is the RAM file. . RAM Real Audio Metafile. It is a pretty straight forward way that Real Networks allowed their Real Player to take more control over their proprietary audio streams. The file format is simply a URL on each line that will be streamed in order by the client. The mime type is the same as other RealAudio files audio/x-pn-realaudio where the pn stands for Progressive Networks the old name of the company. . M3U This next one is the MPEG Layer 3 URL Metafile that has been around for a very long time as a playlist format for MP3 players. It supported URLs pretty early on by some players and got the mime type audio/x-mpegurl and is now used by Icecast and many destination sites such as MP3.com. The format is exactly the same as that of the RAM file, just a list of urls that are separated by line feeds. . PLS This is the playlist files used by Nullsoft's Winamp MP3 Player. Later on it got more widely used by Nullsoft's Shoutcast and has the mime type of audio/x-scpls with the extension .pls. Before shoutcast the mimetype was simply audio/x-pls. As you can see in the example below it looks very much like a standard windows INI file format. Example: [playlist] numberofentries=2 File1= Title1= Length1=<length or -1> File2=<uri> Title2=<title> Length2=<length or -1> . SDP This is the Session Description Protocol [RFC2327] which is heavily used within RTSP and is a standard way of describing how to subscribe to a particular RTP stream. The mime type is application/sdp with the extension .sdp . Sometimes you might see RTSL (Real-Time Streaming Language) floating around. This was an old Real Networks format that has been succeeded by SDP. It's mimetype was application/x-rtsl with the extension of .rtsl . ASX Is a Windows Media Metafile format [MSASX] that is based on early XML standards. It can be found with many extensions such as .wvx, .wax and .asx. I am not aware of a mime type for this format. . SMIL Is the Synchronized Multimedia Integration Language [SMIL20] that is now a W3C Recommendation [W3SYMM]. It was originally developed by Real Networks to provide an HTML-like language to their Real Player that was more focused on multimedia. The mime type is application/smil with the extensions of either .smil or .smi . MHEG Is a hypertext language developed by the ISO group. [MHEG1] [MHEG5] and [MHEG5COR]. It has been adopted by the Digital Audio Visual Council [DAVIC]. It is more used for teleconferencing, broadcasting and television, but close enough related that it receives a mention here. The mime type is application/x-mheg with the extension of .mheg 8. Configuring Apache HTTPD specificly to serve large Audio Files Some of the most common things that you will need to adjust to be able to serve many large audio files via the Apache HTTPD Server. Because of the difference in size between HTML files and Audio files, the MaxClients will need to be adjusted appropriatedly depending on the amount of time listeners end up tieing up a process. If you are serving high quality MP3 files at 128kbps for example you should expect more than 5 minute download times for most people. This will significantly impact your webserver since this means that that process is occupied for the entire time. Because of this you will also want to in crease the TimeOut Directive to a higher number. This is to ensure that connections do not get disconnected half way through a transfer and having that person hit "reload" and connect again. Because of the amount of time the downloads tie up the processes of the server, the smallest footprint of the server in memory would be recommended because that would mean you could run more processes on the machine. After that normal performance tweaks such as max file descriptor changes and longer tcp listen queues apply. 9. Icecast/Shoutcast Protocol. Both protocols are very tightly based on HTTP/1.0. The main difference is a group of new headers such as the icy headers by Shoutcast and the new x-audiocast headers provided by Icecast. A typical shoutcast request from the client. GET / HTTP/1.0 ICY 200 OK icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/"> Winamp</a><BR> icy-notice2:SHOUTcast Distributed Network Audio Server/posix v1.0b<BR> icy-name: Great Songs icy-genre: Jazz icy-url: http://shout.serv.dom/ icy-pub: 1 icy-br: 24 <data><songtitle><data> The icy headers display the song title and other formation including if this stream is public and what the bitrate is. A typical icecast request from the client. GET / HTTP/1.0 Host: icecast.serv.dom x-audiocast-udpport: 6000 Icy-MetaData: 0 Accept: */* HTTP/1.0 200 OK Server: Icecast/VERSION Content-Type: audio/mpeg x-audiocast-name: Great Songs x-audiocast-genre: Jazz x-audiocast-url: http://icecast.serv.dom/ x-audiocast-streamid: x-audiocast-public: 0 x-audiocast-bitrate: 24 x-audiocast-description: served by Icecast <data> NOTE: I am mixing the headers of the controlling client with those form a listening client. This might be better explained at a latter date. The CPAN Perl Package Apache::MP3 by Lincoln Stein implements a little of each which works because MP3 players tend to support both. One of the big differences in implementations between the listening clients is that Icecast uses an out of band UDP channel to update metadata while the Shoutcast server gets it meta data from the client embedded within the MP3 stream. The general meta data for the stream is set up via the icy and x-audiocast HTTP headers. Although the MP3 standard documents were written for interrupted communication it is not very specific on that. So although it doesn't state that there is anything wrong with embedding garbage between MPEG frames the players that do not understand it might make a noisy bleep and chirps because of it. References and Further Reading: [DAVIC] Digital Audio Visual Council <http://www.davic.org/> [FLASH4AUDIO] L. J. Lotus, "Flash 4: Audio Options", ZD, Inc. 2000. <http://www.zdnet.com/devhead/stories/articles/0,4413,2580376,00.html> [HTML4] D. Ragget, A. Le Hors, I. Jacobs, "HTML 4.01 Specification", W3C Recommendation, December, 1999. <http://www.w3.org/TR/html401/> [IANA] Internet Assigned Numbers Authority. <http:/www.iana.org/> [ICECAST] Icecast Open Source Streaming Audio System. <http://www.icecast.org/> [IETFAVT] Audio/Video Transport WG, Internet Engineering Task Force. <http://www.ietf.org/html.charters/avt-charter.html> [IETFMMUSIC] Multiparty Multimedia Session Control WG, Internet Engineering Task Force. <http://www.ietf.org/html.charters/mmusic-charter.html> [IETFSIP] Session Initiation Protocol WG, Internet Engineering Task Force. <http://www.ietf.org/html.charters/sip-charter.html> [IPMULTICAST] Transmit information to a group of recipients via a single transmission by the source, in contrast to unicast. IP Multicast Initiative <http://www.ipmulticast.com/> [MIDISPEC] The International MIDI Association,"MIDI File Format Spec 1.1", <http://www.vanZoest.com/sander/apachecon/2001/midispec.html> [MHEG1] ISO/IEC, "Information Technology - Coding of Multimedia and Hypermedia Information - Part 1: MHEG Object Representation, Base Notation (ASN.1)"; Draft International Standard ISO 13522-1;1997; <http://www.ansi.org/> <http://www.iso.ch/cate/d22153.html> [MHEG5] ISO/IEC, "Information Technology - Coding of Multimedia and Hypermedia Information - Part 5: Support for Base-Level Interactive Applications"; Draft International Standard ISO 13522-5:1997; <http://www.ansi.org/> <http://www.iso.ch/cate/d26876.html> [MHEG5COR] Information Technology - Coding of Multimedia and Hypermedia Information - Part 5: Support for base-level interactive applications - - Technical Corrigendum 1; ISO/IEC 13552-5:1997/Cor.1:1999(E) <http://www.ansi.org/> <http://www.iso.ch/cate/d31582.html> [MSASX] Microsoft Corp. "All About Windows Media Metafiles". October 2000. <http://msdn.microsoft.com/workshop/imedia/windowsmedia/ crcontent/asx.asp> [ORAMP3] S. Hacker; MP3: The Definitive Guide; O'Reilly and Associates, Inc. March, 2000. <http://www.oreilly.com/catalog/mp3/> [RFC2045] N. Freed and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996. <http://www.ietf.org/rfc/2045.txt> [RFC2327] M. Handley and V. Jacobson, "SDP: Session Description Protocol", RFC 2327, April 1998. <http://www.ietf.org/rfc/rfc2327.txt> [RFC3003] M. Nilsson, "The audio/mpeg Media Type", RFC 3003, November 2000. <http://www.ietf.org/rfc/rfc3003.txt> [SHOUTCAST] Nullsoft Shoutcast MP3 Streaming Technology. <http://www.shoutcast.com/> [SMIL20] L. Rutledge, J. van Ossenbruggen, L. Hardman, D. Bulterman, "Anticipating SMIL 2.0: The Developing Cooperative Infrastructure for Multimedia on the Web"; 8th International WWW Conference, Proc. May, 1999. <http://www8.org/w8-papers/3c-hypermedia-video/anticipating/ anticipating.html> [W39CIR] V. Krishnan and S. G. Chang, "Customized Internet Radio"; 9th International WWW Conference Proc. May 2000. <http://www9.org/w9cdrom/353/353.html> [VORBIS] Ogg Vorbis - Open Source Audio Codec <http://www.xiph.org/ogg/vorbis/> [W3SYMM] W3C Synchronized Multimedia Activity (SYMM Working Group); <http://www.w3.org/AudioVideo/> diff --git a/src/kcms/kio/smbrodlg.cpp b/src/kcms/kio/smbrodlg.cpp index 7e0d8e8d..1b4538d0 100644 --- a/src/kcms/kio/smbrodlg.cpp +++ b/src/kcms/kio/smbrodlg.cpp @@ -1,185 +1,185 @@ /* This file is part of the KDE project Copyright (C) 2000 Alexander Neundorf <neundorf@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Own #include "smbrodlg.h" // Qt #include <QtCore/QTextCodec> #include <QLabel> #include <QGridLayout> // KDE #include <kcharsets.h> #include <kcombobox.h> #include <kconfig.h> #include <QDialog> #include <kpluginfactory.h> #include <KLocalizedString> //#include <config-apps.h> #include <KConfigGroup> K_PLUGIN_FACTORY_DECLARATION(KioConfigFactory) SMBRoOptions::SMBRoOptions(QWidget *parent, const QVariantList &/*, const KComponentData &componentData*/) : KCModule(/*componentData.isValid() ? componentData : KioConfigFactory::componentData(),*/ parent) { QGridLayout *layout = new QGridLayout(this ); QLabel *label=new QLabel(i18n("These settings apply to network browsing only."),this); layout->addWidget(label,0,0, 1, 2 ); m_userLe=new QLineEdit(this); label=new QLabel(i18n("Default user name:"),this); label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); label->setBuddy( m_userLe ); layout->addWidget(label,1,0); layout->addWidget(m_userLe,1,1); m_passwordLe=new QLineEdit(this); m_passwordLe->setEchoMode(QLineEdit::Password); label=new QLabel(i18n("Default password:"),this); label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); label->setBuddy( m_passwordLe ); layout->addWidget(label,2,0); layout->addWidget(m_passwordLe,2,1); /* m_workgroupLe=new QLineEdit(this); label=new QLabel(m_workgroupLe,i18n("Workgroup:"),this); layout->addWidget(label,3,0); layout->addWidget(m_workgroupLe,3,1); m_showHiddenShares=new QCheckBox(i18n("Show hidden shares"),this); layout->addWidget(m_showHiddenShares,4,0, 1, 2 ); m_encodingList = new KComboBox( false, this ); QStringList _strList = KCharsets::charsets()->availableEncodingNames(); m_encodingList->addItems( _strList ); label = new QLabel( i18n( "MS Windows encoding:" ), this ); label->setBuddy( m_encodingList ); layout->addWidget( label, 3, 0 ); layout->addWidget( m_encodingList, 3, 1 ); */ layout->addWidget(new QWidget(this),4,0); // connect(m_showHiddenShares, SIGNAL(toggled(bool)), this, SLOT(changed())); connect(m_userLe, SIGNAL(textChanged(QString)), this, SLOT(changed())); connect(m_passwordLe, SIGNAL(textChanged(QString)), this, SLOT(changed())); // connect(m_workgroupLe, SIGNAL(textChanged(QString)), this, SLOT(changed())); // connect( m_encodingList, SIGNAL(activated(QString)), this , SLOT(changed()) ); layout->setRowStretch(4, 1); } SMBRoOptions::~SMBRoOptions() { } void SMBRoOptions::load() { KConfig *cfg = new KConfig(QStringLiteral("kioslaverc")); QString tmp; KConfigGroup group = cfg->group("Browser Settings/SMBro" ); m_userLe->setText(group.readEntry("User")); // m_workgroupLe->setText(group.readEntry("Workgroup")); // m_showHiddenShares->setChecked(group.readEntry("ShowHiddenShares", QVariant(false)).toBool()); //QStringList _strList = KCharsets::charsets()->availableEncodingNames(); //QString m_encoding = QTextCodec::codecForLocale()->name(); //m_encodingList->setCurrentIndex( _strList.indexOf( group.readEntry( "Encoding", m_encoding.toLower() ) ) ); // unscramble QString scrambled = group.readEntry( "Password" ); QString password = QLatin1String(""); for (int i=0; i<scrambled.length()/3; i++) { QChar qc1 = scrambled[i*3]; QChar qc2 = scrambled[i*3+1]; QChar qc3 = scrambled[i*3+2]; unsigned int a1 = qc1.toLatin1() - '0'; unsigned int a2 = qc2.toLatin1() - 'A'; unsigned int a3 = qc3.toLatin1() - '0'; unsigned int num = ((a1 & 0x3F) << 10) | ((a2& 0x1F) << 5) | (a3 & 0x1F); password[i] = QChar((uchar)((num - 17) ^ 173)); // restore } m_passwordLe->setText(password); delete cfg; } void SMBRoOptions::save() { KConfig *cfg = new KConfig(QStringLiteral("kioslaverc")); KConfigGroup group = cfg->group("Browser Settings/SMBro" ); group.writeEntry( "User", m_userLe->text()); // group.writeEntry( "Workgroup", m_workgroupLe->text()); // group.writeEntry( "ShowHiddenShares", m_showHiddenShares->isChecked()); // group.writeEntry( "Encoding", m_encodingList->currentText() ); //taken from Nicola Brodu's smb ioslave //it's not really secure, but at //least better than storing the plain password QString password(m_passwordLe->text()); QString scrambled; for (int i=0; i<password.length(); i++) { QChar c = password[i]; unsigned int num = (c.unicode() ^ 173) + 17; unsigned int a1 = (num & 0xFC00) >> 10; unsigned int a2 = (num & 0x3E0) >> 5; unsigned int a3 = (num & 0x1F); scrambled += (char)(a1+'0'); scrambled += (char)(a2+'A'); scrambled += (char)(a3+'0'); } group.writeEntry( "Password", scrambled); delete cfg; } void SMBRoOptions::defaults() { m_userLe->setText(QLatin1String("")); m_passwordLe->setText(QLatin1String("")); // m_workgroupLe->setText(""); // m_showHiddenShares->setChecked(false); } void SMBRoOptions::changed() { emit KCModule::changed(true); } QString SMBRoOptions::quickHelp() const { return i18n("<h1>Windows Shares</h1><p>Applications using the " "SMB kioslave (like Konqueror) are able to access shared Microsoft " "Windows file systems, if properly configured.</p><p>You can specify " - "here the credentils used to access the shared resources. " + "here the credentials used to access the shared resources. " "Passwords will be stored locally, and scrambled so as to render them " "unreadable to the human eye. For security reasons, you may not want to " "do that, as entries with passwords are clearly indicated as such.</p>"); } diff --git a/src/kcms/kio/useragentdlg.cpp b/src/kcms/kio/useragentdlg.cpp index f4b37a42..862eef6f 100644 --- a/src/kcms/kio/useragentdlg.cpp +++ b/src/kcms/kio/useragentdlg.cpp @@ -1,394 +1,394 @@ /* Original Authors: Copyright (c) Kalle Dalheimer <kalle@kde.org> 1997 Copyright (c) David Faure <faure@kde.org> 1998 Copyright (c) Dirk Mueller <mueller@kde.org> 2000 Completely re-written by: Copyright (C) 2000- Dawit Alemayehu <adawit@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (GPL) version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Own #include "useragentdlg.h" // Local #include "ksaveioconfig.h" #include "useragentinfo.h" #include "useragentselectordlg.h" // Qt #include <QCheckBox> #include <QPushButton> #include <QTreeWidget> #include <QLoggingCategory> // KDE #include <kconfig.h> #include <KConfigGroup> #include <KLocalizedString> #include <kmessagebox.h> #include <http_slave_defaults.h> #include <kpluginfactory.h> Q_DECLARE_LOGGING_CATEGORY(KIO_USERAGENTDLG) Q_LOGGING_CATEGORY(KIO_USERAGENTDLG, "kf5.kio.useragentdlg") K_PLUGIN_FACTORY_DECLARATION (KioConfigFactory) typedef QList<QTreeWidgetItem*> SiteList; typedef SiteList::iterator SiteListIterator; UserAgentDlg::UserAgentDlg (QWidget* parent, const QVariantList&) : KCModule (/*ioConfigFactory::componentData(),*/ parent), m_userAgentInfo (nullptr), m_config (nullptr) { ui.setupUi (this); ui.newButton->setIcon (QIcon::fromTheme(QStringLiteral("list-add"))); ui.changeButton->setIcon (QIcon::fromTheme(QStringLiteral("edit-rename"))); ui.deleteButton->setIcon (QIcon::fromTheme(QStringLiteral("list-remove"))); ui.deleteAllButton->setIcon (QIcon::fromTheme(QStringLiteral("edit-delete"))); } UserAgentDlg::~UserAgentDlg() { delete m_userAgentInfo; delete m_config; } void UserAgentDlg::on_sendUACheckBox_clicked() { configChanged(); } void UserAgentDlg::on_newButton_clicked() { const QPointer<UserAgentSelectorDlg> pdlg (new UserAgentSelectorDlg (m_userAgentInfo, this)); pdlg->setWindowTitle(i18nc ("@title:window", "Add Identification")); if (pdlg->exec() == QDialog::Accepted && pdlg) { if (!handleDuplicate (pdlg->siteName(), pdlg->identity(), pdlg->alias())) { QTreeWidgetItem* item = new QTreeWidgetItem (ui.sitePolicyTreeWidget); item->setText (0, pdlg->siteName()); item->setText (1, pdlg->identity()); item->setText (2, pdlg->alias()); ui.sitePolicyTreeWidget->setCurrentItem (item); configChanged(); } } delete pdlg; } void UserAgentDlg::on_changeButton_clicked() { on_sitePolicyTreeWidget_itemDoubleClicked (ui.sitePolicyTreeWidget->currentItem(), -1); } void UserAgentDlg::on_deleteButton_clicked() { SiteList selectedItems = ui.sitePolicyTreeWidget->selectedItems(); SiteListIterator endIt = selectedItems.end(); QString siteName; for (SiteListIterator it = selectedItems.begin(); it != endIt; ++it) delete (*it); updateButtons(); configChanged(); } void UserAgentDlg::on_deleteAllButton_clicked() { ui.sitePolicyTreeWidget->clear(); updateButtons(); configChanged(); } void UserAgentDlg::on_osNameCheckBox_clicked() { changeDefaultUAModifiers(); } void UserAgentDlg::on_osVersionCheckBox_clicked() { changeDefaultUAModifiers(); } void UserAgentDlg::on_processorTypeCheckBox_clicked() { changeDefaultUAModifiers(); } void UserAgentDlg::on_languageCheckBox_clicked() { changeDefaultUAModifiers(); } void UserAgentDlg::on_sitePolicyTreeWidget_itemDoubleClicked (QTreeWidgetItem* item, int) { if (item) { // Store the current site name... const QString currentSiteName = item->text (0); UserAgentSelectorDlg pdlg (m_userAgentInfo, this); pdlg.setWindowTitle (i18nc ("@title:window", "Modify Identification")); pdlg.setSiteName (currentSiteName); pdlg.setIdentity (item->text (1)); if (pdlg.exec() == QDialog::Accepted) { if (pdlg.siteName() == currentSiteName || !handleDuplicate (pdlg.siteName(), pdlg.identity(), pdlg.alias())) { item->setText (0, pdlg.siteName()); item->setText (1, pdlg.identity()); item->setText (2, pdlg.alias()); configChanged(); } } } } void UserAgentDlg::changeDefaultUAModifiers() { m_ua_keys = ':'; // Make sure it's not empty if (ui.osNameCheckBox->isChecked()) m_ua_keys += 'o'; if (ui.osVersionCheckBox->isChecked()) m_ua_keys += 'v'; if (ui.processorTypeCheckBox->isChecked()) m_ua_keys += 'm'; if (ui.languageCheckBox->isChecked()) m_ua_keys += 'l'; ui.osVersionCheckBox->setEnabled (m_ua_keys.contains ('o')); QString modVal = KProtocolManager::defaultUserAgent (m_ua_keys); if (ui.defaultIdLineEdit->text() != modVal) { ui.defaultIdLineEdit->setText (modVal); configChanged(); } } bool UserAgentDlg::handleDuplicate (const QString& site, const QString& identity, const QString& alias) { SiteList list = ui.sitePolicyTreeWidget->findItems (site, Qt::MatchExactly, 0); if (!list.isEmpty()) { QString msg = i18n ("<qt><center>Found an existing identification for" "<br/><b>%1</b><br/>" "Do you want to replace it?</center>" "</qt>", site); int res = KMessageBox::warningContinueCancel (this, msg, i18nc ("@title:window", "Duplicate Identification"), KGuiItem (i18n ("Replace"))); if (res == KMessageBox::Continue) { list[0]->setText (0, site); list[0]->setText (1, identity); list[0]->setText (2, alias); configChanged(); } return true; } return false; } void UserAgentDlg::configChanged (bool enable) { emit changed (enable); } void UserAgentDlg::updateButtons() { const int selectedItemCount = ui.sitePolicyTreeWidget->selectedItems().count(); const bool hasItems = ui.sitePolicyTreeWidget->topLevelItemCount() > 0; ui.changeButton->setEnabled ( (hasItems && selectedItemCount == 1)); ui.deleteButton->setEnabled ( (hasItems && selectedItemCount > 0)); ui.deleteAllButton->setEnabled (hasItems); } void UserAgentDlg::on_sitePolicyTreeWidget_itemSelectionChanged() { updateButtons(); } void UserAgentDlg::load() { ui.sitePolicyTreeWidget->clear(); if (!m_config) m_config = new KConfig (QStringLiteral("kio_httprc"), KConfig::NoGlobals); else m_config->reparseConfiguration(); if (!m_userAgentInfo) m_userAgentInfo = new UserAgentInfo(); const QStringList list = m_config->groupList(); QStringList::ConstIterator endIt = list.end(); QString agentStr; for (QStringList::ConstIterator it = list.begin(); it != endIt; ++it) { if ( (*it) == QLatin1String("<default>")) continue; KConfigGroup cg (m_config, *it); agentStr = cg.readEntry ("UserAgent"); if (!agentStr.isEmpty()) { QTreeWidgetItem* item = new QTreeWidgetItem (ui.sitePolicyTreeWidget); item->setText (0, (*it).toLower()); item->setText (1, m_userAgentInfo->aliasStr (agentStr)); item->setText (2, agentStr); } } // Update buttons and checkboxes... KConfigGroup cg2 (m_config, QString()); bool b = cg2.readEntry ("SendUserAgent", true); ui.sendUACheckBox->setChecked (b); m_ua_keys = cg2.readEntry ("UserAgentKeys", DEFAULT_USER_AGENT_KEYS).toLower(); ui.defaultIdLineEdit->setText (KProtocolManager::defaultUserAgent (m_ua_keys)); ui.osNameCheckBox->setChecked (m_ua_keys.contains ('o')); ui.osVersionCheckBox->setChecked (m_ua_keys.contains ('v')); ui.processorTypeCheckBox->setChecked (m_ua_keys.contains ('m')); ui.languageCheckBox->setChecked (m_ua_keys.contains ('l')); updateButtons(); configChanged (false); } void UserAgentDlg::defaults() { ui.sitePolicyTreeWidget->clear(); m_ua_keys = QStringLiteral(DEFAULT_USER_AGENT_KEYS); ui.defaultIdLineEdit->setText (KProtocolManager::defaultUserAgent (m_ua_keys)); ui.osNameCheckBox->setChecked (m_ua_keys.contains ('o')); ui.osVersionCheckBox->setChecked (m_ua_keys.contains ('v')); ui.processorTypeCheckBox->setChecked (m_ua_keys.contains ('m')); ui.languageCheckBox->setChecked (m_ua_keys.contains ('l')); ui.sendUACheckBox->setChecked (true); updateButtons(); configChanged(); } void UserAgentDlg::save() { Q_ASSERT (m_config); // Put all the groups except the default into the delete list. QStringList deleteList = m_config->groupList(); //Remove all the groups that DO NOT contain a "UserAgent" entry... QStringList::ConstIterator endIt = deleteList.constEnd(); for (QStringList::ConstIterator it = deleteList.constBegin(); it != endIt; ++it) { if ( (*it) == QLatin1String ("<default>")) continue; KConfigGroup cg (m_config, *it); if (!cg.hasKey ("UserAgent")) deleteList.removeAll (*it); } QString domain; QTreeWidgetItem* item; int itemCount = ui.sitePolicyTreeWidget->topLevelItemCount(); // Save and remove from the delete list all the groups that were // not deleted by the end user. for (int i = 0; i < itemCount; i++) { item = ui.sitePolicyTreeWidget->topLevelItem (i); domain = item->text (0); KConfigGroup cg (m_config, domain); cg.writeEntry ("UserAgent", item->text (2)); deleteList.removeAll (domain); qCDebug (KIO_USERAGENTDLG, "UserAgentDlg::save: Removed [%s] from delete list", domain.toLatin1().constData()); } // Write the global configuration information... KConfigGroup cg (m_config, QString()); cg.writeEntry ("SendUserAgent", ui.sendUACheckBox->isChecked()); cg.writeEntry ("UserAgentKeys", m_ua_keys); // Sync up all the changes so far... m_config->sync(); // If delete list is not empty, delete the specified domains. if (!deleteList.isEmpty()) { // Remove entries from local file. endIt = deleteList.constEnd(); KConfig cfg (QStringLiteral("kio_httprc"), KConfig::SimpleConfig); for (QStringList::ConstIterator it = deleteList.constBegin(); it != endIt; ++it) { KConfigGroup cg (&cfg, *it); cg.deleteEntry ("UserAgent"); qCDebug (KIO_USERAGENTDLG, "UserAgentDlg::save: Deleting UserAgent of group [%s]", (*it).toLatin1().constData()); if (cg.keyList().count() < 1) cg.deleteGroup(); } // Sync up the configuration... cfg.sync(); // Check everything is gone, reset to blank otherwise. m_config->reparseConfiguration(); endIt = deleteList.constEnd(); for (QStringList::ConstIterator it = deleteList.constBegin(); it != endIt; ++it) { KConfigGroup cg (m_config, *it); if (cg.hasKey ("UserAgent")) cg.writeEntry ("UserAgent", QString()); } // Sync up the configuration... m_config->sync(); } KSaveIOConfig::updateRunningIOSlaves (this); configChanged (false); } QString UserAgentDlg::quickHelp() const { return i18n ("<h1>Browser Identification</h1>" - "<p>The browser-identification module allows you to have full " + "<p>The browser-identification module allows you to have " "full control over how KDE applications using the HTTP " "protocol (like Konqueror) will identify itself to web sites " "you browse.</p>" "<p>This ability to fake identification is necessary because " "some web sites do not display properly when they detect that " "they are not talking to current versions of either Netscape " "Navigator or Internet Explorer, even if the browser actually " "supports all the necessary features to render those pages " "properly. " "For such sites, you can use this feature to try to browse " "them. Please understand that this might not always work, since " "such sites might be using non-standard web protocols and or " "specifications.</p>" "<p><u>NOTE:</u> To obtain specific help on a particular section " "of the dialog box, simply click on the quick help button on " "the window title bar, then click on the section " "for which you are seeking help.</p>"); } diff --git a/src/widgets/accessmanager.h b/src/widgets/accessmanager.h index 02f28692..b9427efe 100644 --- a/src/widgets/accessmanager.h +++ b/src/widgets/accessmanager.h @@ -1,364 +1,364 @@ /* * This file is part of the KDE project. * * Copyright (C) 2008 - 2009 Urs Wolfer <uwolfer @ kde.org> * Copyright (C) 2009 - 2012 Dawit Alemayehu <adawit @ kde.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef KIO_ACCESSMANAGER_H #define KIO_ACCESSMANAGER_H #include <kio/global.h> #include "kiowidgets_export.h" #include <qwindowdefs.h> // WId #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkRequest> #include <QtNetwork/QNetworkCookieJar> class QWidget; namespace KIO { /** * @short A KDE implementation of QNetworkAccessManager. * * Use this class instead of QNetworkAccessManager if you want to integrate * with KDE's KIO and KCookieJar modules for network operations and cookie * handling respectively. * * Here is a simple example that shows how to set the QtWebKit module to use KDE's * KIO for its network operations: * @code * QWebView *view = new QWebView(this); * KIO::Integration::AccessManager *manager = new KIO::Integration::AccessManager(view); * view->page()->setNetworkAccessManager(manager); * @endcode * * To access member functions in the cookiejar class at a later point in your * code simply downcast the pointer returned by QWebPage::networkAccessManager * as follows: * @code * KIO::Integration::AccessManager *manager = qobject_cast<KIO::Integration::AccessManager*>(view->page()->accessManager()); * @endcode * * Please note that this class is in the KIO namespace for backward compatablity. * You should use KIO::Integration::AccessManager to access this class in your * code. * * <b>IMPORTANT</b>This class is not a replacement for the standard KDE API. * It should ONLY be used to provide KDE integration in applications that * cannot use the standard KDE API directly. * * @author Urs Wolfer \<uwolfer @ kde.org\> * @author Dawit Alemayehu \<adawit @ kde.org\> * * @deprecated Use the KIO::Integration::AccessManager typedef to access this class instead. * @since 4.3 */ class KIOWIDGETS_EXPORT AccessManager : public QNetworkAccessManager { Q_OBJECT public: /*! * Extensions to QNetworkRequest::Attribute enums. * @since 4.3.2 */ enum Attribute { MetaData = QNetworkRequest::User, /** < Used to send KIO MetaData back and forth. type: QVariant::Map. */ KioError /**< Used to send KIO error codes that cannot be mapped into QNetworkReply::NetworkError. type: QVariant::Int */ }; /** * Constructor */ AccessManager(QObject *parent); /** * Destructor */ virtual ~AccessManager(); /** * Set @p allowed to false if you don't want any external content to be fetched. * By default external content is fetched. */ void setExternalContentAllowed(bool allowed); /** * Returns true if external content is going to be fetched. * * @see setExternalContentAllowed */ bool isExternalContentAllowed() const; /** * Sets the cookiejar's window id to @p id. * * This is a convenience function that allows you to set the cookiejar's * window id. Note that this function does nothing unless the cookiejar in * use is of type KIO::Integration::CookieJar. * * By default the cookiejar's window id is set to false. Make sure you call * this function and set the window id to its proper value when create an * instance of this object. Otherwise, the KDE cookiejar will not be able * to properly manage session based cookies. * * @see KIO::Integration::CookieJar::setWindowId. * @since 4.4 * @deprecated Use setWindow */ #ifndef KIOWIDGETS_NO_DEPRECATED KIOWIDGETS_DEPRECATED void setCookieJarWindowId(WId id); #endif /** * Sets the window associated with this network access manager. * * Note that @p widget will be used as a parent for dialogs in KIO as well * as the cookie jar. If @p widget is not a window, this function will * invoke @ref QWidget::window() to obtain the window for the given widget. * * @see KIO::Integration::CookieJar::setWindow. * @since 4.7 */ void setWindow(QWidget *widget); /** * Returns the cookiejar's window id. * * This is a convenience function that returns the window id associated * with the cookiejar. Note that this function will return a 0 if the * cookiejar is not of type KIO::Integration::CookieJar or a window id * has not yet been set. * * @see KIO::Integration::CookieJar::windowId. * @since 4.4 * @deprecated Use KIO::Integration::CookieJar::windowId */ #ifndef KIOWIDGETS_NO_DEPRECATED KIOWIDGETS_DEPRECATED WId cookieJarWindowid() const; #endif /** * Returns the window associated with this network access manager. * * @see setWindow * @since 4.7 */ QWidget *window() const; /** * Returns a reference to the temporary meta data container. * * See kdelibs/kio/DESIGN.metadata for list of supported KIO meta data. * * Use this function when you want to set per request KIO meta data that * will be removed after it has been sent once. * * @since 4.4 */ KIO::MetaData &requestMetaData(); /** * Returns a reference to the persistent meta data container. * * See kdelibs/kio/DESIGN.metadata for list of supported KIO meta data. * * Use this function when you want to set per session KIO meta data that * will be sent with every request. * * Unlike @p requestMetaData, the meta data values set using the reference * returned by this function will not be deleted and will be sent with every * request. * * @since 4.4 */ KIO::MetaData &sessionMetaData(); /** * Puts the ioslave associated with the given @p reply on hold. * * This function is intended to make possible the implementation of * the special case mentioned in KIO::get's documentation within the * KIO-QNAM integration. * * @see KIO::get. * @since 4.6 */ static void putReplyOnHold(QNetworkReply *reply); /** * Sets the network reply object to emit readyRead when it receives meta data. * * Meta data is any information that is not the actual content itself, e.g. * HTTP response headers of the HTTP protocol. * * Calling this function will force the code connecting to QNetworkReply's * readyRead signal to prematurely start dealing with the content that might * not yet have arrived. However, it is essential to make the put ioslave on * hold functionality of KIO work in libraries like QtWebKit. * * @see QNetworkReply::metaDataChanged * @since 4.7 */ void setEmitReadyReadOnMetaDataChange(bool); protected: /** * Reimplemented for internal reasons, the API is not affected. * * @see QNetworkAccessManager::createRequest * @internal */ QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData = nullptr) Q_DECL_OVERRIDE; private: class AccessManagerPrivate; AccessManagerPrivate *const d; }; namespace Integration { // KDE5: Move AccessManager into the KIO::Integration namespace. typedef KIO::AccessManager AccessManager; /** * Maps KIO SSL meta data into the given QSslConfiguration object. * * @since 4.5 * @return true if @p metadata contains ssl information and the mapping succeeded. */ KIOWIDGETS_EXPORT bool sslConfigFromMetaData(const KIO::MetaData &metadata, QSslConfiguration &sslconfig); /** * @short A KDE implementation of QNetworkCookieJar. * * Use this class in place of QNetworkCookieJar if you want to integrate with * KDE's cookiejar instead of the one that comes with Qt. * * Here is a simple example that shows how to set the QtWebKit module to use KDE's * cookiejar: * @code * QWebView *view = new QWebView(this); * KIO::Integration::CookieJar *cookieJar = new KIO::Integration::CookieJar; * cookieJar->setWindowId(view->window()->winId()); * view->page()->networkAccessManager()->setCookieJar(cookieJar); * @endcode * * To access member functions in the cookiejar class at a later point in your * code simply downcast the pointer returned by QNetworkAccessManager::cookieJar * as follows: * @code * KIO::Integration::CookieJar *cookieJar = qobject_cast<KIO::Integration::CookieJar*>(view->page()->accessManager()->cookieJar()); * @endcode * * <b>IMPORTANT</b>This class is not a replacement for the standard KDE API. - * It should ONLY be used to to provide KDE integration in applications that + * It should ONLY be used to provide KDE integration in applications that * cannot use the standard KDE API directly. * * @see QNetworkAccessManager::setCookieJar for details. * * @author Dawit Alemayehu \<adawit @ kde.org\> * @since 4.4 */ class KIOWIDGETS_EXPORT CookieJar : public QNetworkCookieJar { Q_OBJECT public: /** * Constructs a KNetworkCookieJar with parent @p parent. */ explicit CookieJar(QObject *parent = nullptr); /** * Destroys the KNetworkCookieJar. */ ~CookieJar(); /** * Returns the currently set window id. The default value is -1. */ WId windowId() const; /** * Sets the window id of the application. * * This value is used by KDE's cookiejar to manage session cookies, namely * to delete them when the last application referring to such cookies is * closed by the end user. * * @see QWidget::window() * @see QWidget::winId() * * @param id the value of @ref QWidget::winId() from the window that contains your widget. */ void setWindowId(WId id); /** * Reparse the KDE cookiejar configuration file. */ void reparseConfiguration(); /** * Reimplemented for internal reasons, the API is not affected. * * @see QNetworkCookieJar::cookiesForUrl * @internal */ QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const Q_DECL_OVERRIDE; /** * Reimplemented for internal reasons, the API is not affected. * * @see QNetworkCookieJar::setCookiesFromUrl * @internal */ bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) Q_DECL_OVERRIDE; /** * Returns true if persistent caching of cookies is disabled. * * @see setDisableCookieStorage * @since 4.6 */ bool isCookieStorageDisabled() const; /** * Prevent persistent storage of cookies. * * Call this function if you do not want cookies to be stored locally for * later access without disabling the cookiejar. All cookies will be discarded * once the sessions that are using the cookie are done. * * @since 4.6 */ void setDisableCookieStorage(bool disable); private: class CookieJarPrivate; CookieJarPrivate *const d; }; } } #endif // KIO_ACCESSMANAGER_H