diff --git a/src/network-web/downloader.cpp b/src/network-web/downloader.cpp index ebebb6c96..67ebd10e1 100755 --- a/src/network-web/downloader.cpp +++ b/src/network-web/downloader.cpp @@ -64,8 +64,8 @@ void Downloader::downloadFile(const QString &url, int timeout, bool protected_co runGetRequest(request); } -void Downloader::uploadData(const QString &url, const QByteArray &data, int timeout, - bool protected_contents, const QString &username, const QString &password) { +void Downloader::uploadData(const QString &url, const QByteArray &data, QNetworkAccessManager::Operation operation, + int timeout, bool protected_contents, const QString &username, const QString &password) { QNetworkRequest request; QString non_const_url = url; @@ -90,7 +90,12 @@ void Downloader::uploadData(const QString &url, const QByteArray &data, int time m_targetUsername = username; m_targetPassword = password; - runPostRequest(request, m_inputData); + if (operation == QNetworkAccessManager::PostOperation) { + runPostRequest(request, m_inputData); + } + else { + runPutRequest(request, m_inputData); + } } void Downloader::finished() { @@ -123,6 +128,9 @@ void Downloader::finished() { else if (reply_operation == QNetworkAccessManager::PostOperation) { runPostRequest(request, m_inputData); } + else if (reply_operation == QNetworkAccessManager::PutOperation) { + runPutRequest(request, m_inputData); + } } else { // No redirection is indicated. Final file is obtained in our "reply" object. @@ -148,11 +156,23 @@ void Downloader::progressInternal(qint64 bytes_received, qint64 bytes_total) { void Downloader::timeout() { if (m_activeReply != NULL) { - // Download action timed-out, too slow connection or target is no reachable. + // Download action timed-out, too slow connection or target is not reachable. m_activeReply->abort(); } } +void Downloader::runPutRequest(const QNetworkRequest &request, const QByteArray &data) { + m_timer->start(); + m_activeReply = m_downloadManager->put(request, data); + + m_activeReply->setProperty("protected", m_targetProtected); + m_activeReply->setProperty("username", m_targetUsername); + m_activeReply->setProperty("password", m_targetPassword); + + connect(m_activeReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(progressInternal(qint64,qint64))); + connect(m_activeReply, SIGNAL(finished()), this, SLOT(finished())); +} + void Downloader::runPostRequest(const QNetworkRequest &request, const QByteArray &data) { m_timer->start(); m_activeReply = m_downloadManager->post(request, data); diff --git a/src/network-web/downloader.h b/src/network-web/downloader.h index e537640ba..cb7b6beac 100755 --- a/src/network-web/downloader.h +++ b/src/network-web/downloader.h @@ -52,8 +52,9 @@ class Downloader : public QObject { // Performs asynchronous upload of given data as HTTP POST. // User needs to setup "Content-Encoding" header which // matches encoding of the data. - void uploadData(const QString &url, const QByteArray &data, int timeout = DOWNLOAD_TIMEOUT, - bool protected_contents = false, const QString &username = QString(), const QString &password = QString()); + void uploadData(const QString &url, const QByteArray &data, QNetworkAccessManager::Operation operation, + int timeout = DOWNLOAD_TIMEOUT, bool protected_contents = false, + const QString &username = QString(), const QString &password = QString()); signals: // Emitted when new progress is known. @@ -71,6 +72,7 @@ class Downloader : public QObject { void timeout(); private: + void runPutRequest(const QNetworkRequest &request, const QByteArray &data); void runPostRequest(const QNetworkRequest &request, const QByteArray &data); void runGetRequest(const QNetworkRequest &request); diff --git a/src/network-web/networkfactory.cpp b/src/network-web/networkfactory.cpp index c14293fe8..dbb175509 100755 --- a/src/network-web/networkfactory.cpp +++ b/src/network-web/networkfactory.cpp @@ -150,17 +150,27 @@ QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QList &u NetworkResult NetworkFactory::uploadData(const QString &url, int timeout, const QByteArray &input_data, const QString &input_content_type, QByteArray &output, - bool protected_contents, const QString &username, const QString &password) { + QNetworkAccessManager::Operation operation, bool protected_contents, + const QString &username, const QString &password, bool forcefully_embed_basic_header) { Downloader downloader; QEventLoop loop; NetworkResult result; downloader.appendRawHeader("Content-Type", input_content_type.toLocal8Bit()); + if (forcefully_embed_basic_header) { + QString concatenated = username + ":" + password; + QByteArray data = concatenated.toLocal8Bit().toBase64(); + QString headerData = "Basic " + data; + + downloader.appendRawHeader("Authorization", headerData.toLocal8Bit()); + } + // We need to quit event loop when the download finishes. QObject::connect(&downloader, SIGNAL(completed(QNetworkReply::NetworkError)), &loop, SLOT(quit())); - downloader.uploadData(url, input_data, timeout, protected_contents, username, password); + downloader.uploadData(url, input_data, operation, + timeout, protected_contents, username, password); loop.exec(); output = downloader.lastOutputData(); result.first = downloader.lastOutputError(); diff --git a/src/network-web/networkfactory.h b/src/network-web/networkfactory.h index 224a4c5eb..51541e262 100755 --- a/src/network-web/networkfactory.h +++ b/src/network-web/networkfactory.h @@ -45,8 +45,9 @@ class NetworkFactory { static NetworkResult uploadData(const QString &url, int timeout, const QByteArray &input_data, const QString &input_content_type, QByteArray &output, + QNetworkAccessManager::Operation operation, bool protected_contents = false, const QString &username = QString(), - const QString &password = QString()); + const QString &password = QString(), bool forcefully_embed_basic_header = false); static NetworkResult downloadFeedFile(const QString &url, int timeout, QByteArray &output, bool protected_contents = false, const QString &username = QString(), diff --git a/src/network-web/silentnetworkaccessmanager.cpp b/src/network-web/silentnetworkaccessmanager.cpp index d19e75918..9039701d8 100755 --- a/src/network-web/silentnetworkaccessmanager.cpp +++ b/src/network-web/silentnetworkaccessmanager.cpp @@ -28,7 +28,7 @@ QPointer SilentNetworkAccessManager::s_instance; SilentNetworkAccessManager::SilentNetworkAccessManager(QObject *parent) : BaseNetworkAccessManager(parent) { connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), - this, SLOT(onAuthenticationRequired(QNetworkReply*,QAuthenticator*))); + this, SLOT(onAuthenticationRequired(QNetworkReply*,QAuthenticator*)), Qt::DirectConnection); } SilentNetworkAccessManager::~SilentNetworkAccessManager() { @@ -43,9 +43,7 @@ SilentNetworkAccessManager *SilentNetworkAccessManager::instance() { return s_instance; } -void SilentNetworkAccessManager::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) { - QList keys = authenticator->options().keys(); - +void SilentNetworkAccessManager::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) { if (reply->property("protected").toBool()) { // This feed contains authentication information, it is good. authenticator->setUser(reply->property("username").toString()); diff --git a/src/network-web/silentnetworkaccessmanager.h b/src/network-web/silentnetworkaccessmanager.h index 69ea1964d..6877518e6 100755 --- a/src/network-web/silentnetworkaccessmanager.h +++ b/src/network-web/silentnetworkaccessmanager.h @@ -36,9 +36,9 @@ class SilentNetworkAccessManager : public BaseNetworkAccessManager { // Returns pointer to global silent network manager static SilentNetworkAccessManager *instance(); - protected slots: + public slots: // This cannot do any GUI stuff. - void onAuthenticationRequired(QNetworkReply * reply, QAuthenticator *authenticator); + void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator); private: static QPointer s_instance; diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index ec138bb16..b4e76f440 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -299,6 +299,26 @@ QStringList ServiceRoot::textualFeedIds(const QList &feeds) const { return stringy_ids; } +QStringList ServiceRoot::customIDsOfMessages(const QList > &changes) { + QStringList list; + + for (int i = 0; i < changes.size(); i++) { + list.append(changes.at(i).first.m_customId); + } + + return list; +} + +QStringList ServiceRoot::customIDsOfMessages(const QList &messages) { + QStringList list; + + foreach (const Message &message, messages) { + list.append(message.m_customId); + } + + return list; +} + int ServiceRoot::accountId() const { return m_accountId; } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 93ebdec0d..89821de9f 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -176,6 +176,9 @@ class ServiceRoot : public RootItem { QStringList textualFeedIds(const QList &feeds) const; + QStringList customIDsOfMessages(const QList > &changes); + QStringList customIDsOfMessages(const QList &messages); + // Takes lists of feeds/categories and assembles them into the tree structure. void assembleCategories(Assignment categories); void assembleFeeds(Assignment feeds); diff --git a/src/services/owncloud/network/owncloudnetworkfactory.cpp b/src/services/owncloud/network/owncloudnetworkfactory.cpp index b9c6b324f..da91c7b0a 100755 --- a/src/services/owncloud/network/owncloudnetworkfactory.cpp +++ b/src/services/owncloud/network/owncloudnetworkfactory.cpp @@ -30,7 +30,7 @@ OwnCloudNetworkFactory::OwnCloudNetworkFactory() - : m_url(QString()), m_forceServerSideUpdate(false), + : m_url(QString()), m_fixedUrl(QString()), m_forceServerSideUpdate(false), m_authUsername(QString()), m_authPassword(QString()), m_urlUser(QString()), m_urlStatus(QString()), m_urlFolders(QString()), m_urlFeeds(QString()), m_urlMessages(QString()), m_userId(QString()) { } @@ -44,21 +44,20 @@ QString OwnCloudNetworkFactory::url() const { void OwnCloudNetworkFactory::setUrl(const QString &url) { m_url = url; - QString working_url; if (url.endsWith('/')) { - working_url = url; + m_fixedUrl = url; } else { - working_url = url + '/'; + m_fixedUrl = url + '/'; } // Store endpoints. - m_urlUser = working_url + API_PATH + "user"; - m_urlStatus = working_url + API_PATH + "status"; - m_urlFolders = working_url + API_PATH + "folders"; - m_urlFeeds = working_url + API_PATH + "feeds"; - m_urlMessages = working_url + API_PATH + "items?id=%1&batchSize=%2&type=%3"; + m_urlUser = m_fixedUrl + API_PATH + "user"; + m_urlStatus = m_fixedUrl + API_PATH + "status"; + m_urlFolders = m_fixedUrl + API_PATH + "folders"; + m_urlFeeds = m_fixedUrl + API_PATH + "feeds"; + m_urlMessages = m_fixedUrl + API_PATH + "items?id=%1&batchSize=%2&type=%3"; } bool OwnCloudNetworkFactory::forceServerSideUpdate() const { @@ -182,6 +181,54 @@ OwnCloudGetMessagesResponse OwnCloudNetworkFactory::getMessages(int feed_id) { return msgs_response; } +QNetworkReply::NetworkError OwnCloudNetworkFactory::markMessagesRead(RootItem::ReadStatus status, + const QStringList &custom_ids) { + QList var_ids; + QtJson::JsonObject json; + QtJson::JsonArray ids; + QByteArray raw_output; + + QString final_url; + + if (status == RootItem::Read) { + final_url = m_fixedUrl + API_PATH + "items/read/multiple"; + } + else { + final_url = m_fixedUrl + API_PATH + "items/unread/multiple"; + } + + foreach (const QString &id, custom_ids) { + var_ids.append(id.toInt()); + } + + ids.append(var_ids); + json["items"] = ids; + + NetworkResult network_reply = NetworkFactory::uploadData(final_url, + qApp->settings()->value(GROUP(Feeds), + SETTING(Feeds::UpdateTimeout)).toInt(), + QtJson::serialize(json), + "application/json", + raw_output, + QNetworkAccessManager::PutOperation, + true, m_authUsername, m_authPassword, + true); + + if (network_reply.first != QNetworkReply::NoError) { + qWarning("ownCloud: Marking messages as (un)read failed with error %d.", network_reply.first); + } + + return (m_lastError = network_reply.first); +} + +QNetworkReply::NetworkError OwnCloudNetworkFactory::markMessagesStarred(const QList &custom_ids) { + return QNetworkReply::NoError; +} + +QNetworkReply::NetworkError OwnCloudNetworkFactory::markMessagesUnstarred(const QList &custom_ids) { + return QNetworkReply::NoError; +} + QString OwnCloudNetworkFactory::userId() const { return m_userId; } diff --git a/src/services/owncloud/network/owncloudnetworkfactory.h b/src/services/owncloud/network/owncloudnetworkfactory.h index 0a5d2fb8a..0eb1b6055 100755 --- a/src/services/owncloud/network/owncloudnetworkfactory.h +++ b/src/services/owncloud/network/owncloudnetworkfactory.h @@ -25,6 +25,7 @@ #include "qt-json/json.h" #include "core/message.h" +#include "services/abstract/rootitem.h" class OwnCloudResponse { @@ -121,8 +122,13 @@ class OwnCloudNetworkFactory { // Get messages for given feed. OwnCloudGetMessagesResponse getMessages(int feed_id); + QNetworkReply::NetworkError markMessagesRead(RootItem::ReadStatus status, const QStringList &custom_ids); + QNetworkReply::NetworkError markMessagesStarred(const QList &custom_ids); + QNetworkReply::NetworkError markMessagesUnstarred(const QList &custom_ids); + private: QString m_url; + QString m_fixedUrl; bool m_forceServerSideUpdate; QString m_authUsername; QString m_authPassword; @@ -134,7 +140,6 @@ class OwnCloudNetworkFactory { QString m_urlFolders; QString m_urlFeeds; QString m_urlMessages; - QString m_userId; }; diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index 50ada4343..0a19028fc 100755 --- a/src/services/owncloud/owncloudserviceroot.cpp +++ b/src/services/owncloud/owncloudserviceroot.cpp @@ -112,6 +112,35 @@ OwnCloudNetworkFactory *OwnCloudServiceRoot::network() const { return m_network; } +bool OwnCloudServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, + RootItem::ReadStatus read) { + Q_UNUSED(selected_item) + + QNetworkReply::NetworkError reply = network()->markMessagesRead(read, customIDsOfMessages(messages)); + return reply == QNetworkReply::NoError; +} + +bool OwnCloudServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, + const QList > &changes) { + Q_UNUSED(selected_item) + + QNetworkReply::NetworkError reply; + + /*if (read == RootItem::Read) { + //reply = network()->markMessagesRead(); + } + else { + reply = network()->markMessagesUnread(); + }*/ + + if (reply == QNetworkReply::NoError) { + return true; + } + else { + return false; + } +} + void OwnCloudServiceRoot::updateTitle() { QString host = QUrl(m_network->url()).host(); diff --git a/src/services/owncloud/owncloudserviceroot.h b/src/services/owncloud/owncloudserviceroot.h index 6b9088714..7650374c8 100755 --- a/src/services/owncloud/owncloudserviceroot.h +++ b/src/services/owncloud/owncloudserviceroot.h @@ -45,6 +45,9 @@ class OwnCloudServiceRoot : public ServiceRoot { OwnCloudNetworkFactory *network() const; + bool onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); + bool onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes); + void updateTitle(); void saveAccountDataToDatabase(); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index f9b8fe380..a70ad7c1f 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -86,7 +86,9 @@ TtRssLoginResponse TtRssNetworkFactory::login() { QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, qApp->settings()->value(GROUP(Feeds), - SETTING(Feeds::UpdateTimeout)).toInt(), QtJson::serialize(json), CONTENT_TYPE, result_raw, + SETTING(Feeds::UpdateTimeout)).toInt(), + QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); TtRssLoginResponse login_response(QString::fromUtf8(result_raw)); @@ -113,6 +115,7 @@ TtRssResponse TtRssNetworkFactory::logout() { NetworkResult network_reply = NetworkFactory::uploadData(m_url, qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(), QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); m_lastError = network_reply.first; @@ -143,6 +146,7 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories() { const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); TtRssGetFeedsCategoriesResponse result(QString::fromUtf8(result_raw)); @@ -152,6 +156,7 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories() { json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); result = TtRssGetFeedsCategoriesResponse(QString::fromUtf8(result_raw)); } @@ -181,6 +186,7 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, int lim const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); TtRssGetHeadlinesResponse result(QString::fromUtf8(result_raw)); @@ -190,6 +196,7 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, int lim json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); result = TtRssGetHeadlinesResponse(QString::fromUtf8(result_raw)); } @@ -215,6 +222,7 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); TtRssUpdateArticleResponse result(QString::fromUtf8(result_raw)); @@ -224,6 +232,7 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); result = TtRssUpdateArticleResponse(QString::fromUtf8(result_raw)); } @@ -253,6 +262,7 @@ TtRssSubscribeToFeedResponse TtRssNetworkFactory::subscribeToFeed(const QString const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); TtRssSubscribeToFeedResponse result(QString::fromUtf8(result_raw)); @@ -262,6 +272,7 @@ TtRssSubscribeToFeedResponse TtRssNetworkFactory::subscribeToFeed(const QString json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); result = TtRssSubscribeToFeedResponse(QString::fromUtf8(result_raw)); } @@ -283,6 +294,7 @@ TtRssUnsubscribeFeedResponse TtRssNetworkFactory::unsubscribeFeed(int feed_id) { const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); TtRssUnsubscribeFeedResponse result(QString::fromUtf8(result_raw)); @@ -292,6 +304,7 @@ TtRssUnsubscribeFeedResponse TtRssNetworkFactory::unsubscribeFeed(int feed_id) { json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, timeout, QtJson::serialize(json), CONTENT_TYPE, result_raw, + QNetworkAccessManager::PostOperation, m_authIsUsed, m_authUsername, m_authPassword); result = TtRssUnsubscribeFeedResponse(QString::fromUtf8(result_raw)); } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index aec8bdd80..4307d19f0 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -513,23 +513,3 @@ void TtRssServiceRoot::syncIn() { setIcon(original_icon); itemChanged(QList() << this); } - -QStringList TtRssServiceRoot::customIDsOfMessages(const QList > &changes) { - QStringList list; - - for (int i = 0; i < changes.size(); i++) { - list.append(changes.at(i).first.m_customId); - } - - return list; -} - -QStringList TtRssServiceRoot::customIDsOfMessages(const QList &messages) { - QStringList list; - - foreach (const Message &message, messages) { - list.append(message.m_customId); - } - - return list; -} diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index b33dec465..e9793cfa3 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -59,7 +59,6 @@ class TtRssServiceRoot : public ServiceRoot { QStringList customIDSOfMessagesForItem(RootItem *item); bool markFeedsReadUnread(QList items, ReadStatus read); - void saveAccountDataToDatabase(); void updateTitle(); void completelyRemoveAllData(); @@ -70,9 +69,6 @@ class TtRssServiceRoot : public ServiceRoot { void syncIn(); private: - QStringList customIDsOfMessages(const QList > &changes); - QStringList customIDsOfMessages(const QList &messages); - void loadFromDatabase(); TtRssRecycleBin *m_recycleBin;