From 69fdac6473e77e3b287479a245f46bbb7e4d9561 Mon Sep 17 00:00:00 2001 From: haroon0x Date: Tue, 12 May 2026 23:43:09 +0530 Subject: [PATCH 1/2] Implement persistent Friend Requests page (#1794) --- retroshare-gui/src/CMakeLists.txt | 2 + .../src/gui/FriendRequestsDialog.cpp | 386 ++++++++++++++++++ retroshare-gui/src/gui/FriendRequestsDialog.h | 98 +++++ retroshare-gui/src/gui/FriendsDialog.cpp | 18 + retroshare-gui/src/gui/FriendsDialog.h | 3 + retroshare-gui/src/retroshare-gui.pro | 2 + 6 files changed, 509 insertions(+) create mode 100644 retroshare-gui/src/gui/FriendRequestsDialog.cpp create mode 100644 retroshare-gui/src/gui/FriendRequestsDialog.h diff --git a/retroshare-gui/src/CMakeLists.txt b/retroshare-gui/src/CMakeLists.txt index 71dd6770f..ae729bb7d 100644 --- a/retroshare-gui/src/CMakeLists.txt +++ b/retroshare-gui/src/CMakeLists.txt @@ -37,6 +37,7 @@ list( src/gui/MainWindow.cpp src/gui/NetworkView.cpp src/gui/FriendsDialog.cpp + src/gui/FriendRequestsDialog.cpp src/gui/ServicePermissionDialog.cpp src/gui/RemoteDirModel.cpp src/gui/RsAutoUpdatePage.cpp @@ -433,6 +434,7 @@ list( src/gui/AboutWidget.h src/gui/NetworkView.h src/gui/FriendsDialog.h + src/gui/FriendRequestsDialog.h src/gui/ServicePermissionDialog.h src/gui/RemoteDirModel.h src/gui/RetroShareLink.h diff --git a/retroshare-gui/src/gui/FriendRequestsDialog.cpp b/retroshare-gui/src/gui/FriendRequestsDialog.cpp new file mode 100644 index 000000000..c4ffc0bc0 --- /dev/null +++ b/retroshare-gui/src/gui/FriendRequestsDialog.cpp @@ -0,0 +1,386 @@ +/******************************************************************************* + * gui/FriendRequestsDialog.cpp * + * * + * Copyright (C) 2026 Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "FriendRequestsDialog.h" +#include "gui/common/RSFeedWidget.h" +#include "gui/feeds/SecurityItem.h" +#include "gui/chat/ChatDialog.h" +#include "settings/rsharesettings.h" +#include "util/qtthreadsutils.h" + +FriendRequestsDialog::FriendRequestsDialog(QWidget *parent) + : QWidget(parent), mAuthEventHandlerId(0), mFriendEventHandlerId(0) +{ + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setContentsMargins(0, 0, 0, 0); + vLayout->setSpacing(0); + + /* Header bar */ + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->setContentsMargins(6, 4, 6, 4); + hLayout->setSpacing(6); + + QLabel *headerIcon = new QLabel(this); + headerIcon->setPixmap(QPixmap(":/images/user/user_request48.png").scaled(24, 24, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + headerIcon->setMaximumSize(24, 24); + hLayout->addWidget(headerIcon); + + QLabel *headerLabel = new QLabel(tr("Friend Requests"), this); + QFont headerFont = headerLabel->font(); + headerFont.setPointSize(11); + headerFont.setBold(true); + headerLabel->setFont(headerFont); + hLayout->addWidget(headerLabel); + + hLayout->addStretch(); + + mClearAllButton = new QPushButton(tr("Clear All"), this); + mClearAllButton->setToolTip(tr("Remove all friend request entries")); + connect(mClearAllButton, SIGNAL(clicked()), this, SLOT(clearAll())); + hLayout->addWidget(mClearAllButton); + + vLayout->addLayout(hLayout); + + /* Feed widget */ + mFeedWidget = new RSFeedWidget(this); + mFeedWidget->setPlaceholderText(tr("No friend requests")); + mFeedWidget->enableRemove(true); + mFeedWidget->setSortRole(FEED_TREEWIDGET_SORTROLE, Qt::DescendingOrder); + vLayout->addWidget(mFeedWidget); + + connect(mFeedWidget, SIGNAL(feedCountChanged()), this, SLOT(updateCount())); + + setLayout(vLayout); + + /* Register event handlers */ + rsEvents->registerEventsHandler( + [this](std::shared_ptr event) { + handleAuthSslEvent(event); + }, + mAuthEventHandlerId, RsEventType::AUTHSSL_CONNECTION_AUTENTICATION); + + rsEvents->registerEventsHandler( + [this](std::shared_ptr event) { + handleFriendListEvent(event); + }, + mFriendEventHandlerId, RsEventType::FRIEND_LIST); + + /* Load persistent state and keyring peers */ + loadStoredRequests(); +} + +FriendRequestsDialog::~FriendRequestsDialog() +{ + rsEvents->unregisterEventsHandler(mAuthEventHandlerId); + rsEvents->unregisterEventsHandler(mFriendEventHandlerId); +} + +void FriendRequestsDialog::loadStoredRequests() +{ + Settings->beginGroup("FriendRequests"); + QStringList rejected = Settings->value("Rejected").toStringList(); + QVariantList list = Settings->value("StoredAttempts").toList(); + Settings->endGroup(); + + for (const QString &s : rejected) + mRejectedPeers.insert(s); + + for (const QVariant &v : list) + { + QVariantMap map = v.toMap(); + AttemptEntry entry; + entry.pgpId = map["pgpId"].toString(); + entry.sslId = map["sslId"].toString(); + entry.sslCn = map["sslCn"].toString(); + entry.locator = map["locator"].toString(); + entry.timestamp = map["timestamp"].toLongLong(); + + /* Ignore if rejected */ + QString rejKey = entry.pgpId.isEmpty() ? entry.sslId : entry.pgpId; + if (mRejectedPeers.contains(rejKey)) + continue; + + /* Ignore if already a friend */ + if (!entry.pgpId.isEmpty() && rsPeers && rsPeers->isPgpFriend(RsPgpId(entry.pgpId.toStdString()))) + continue; + + /* Ensure no duplicates */ + if (!mStoredAttempts.contains(entry)) + { + mStoredAttempts.append(entry); + addSecurityItem(entry); + } + } + + /* Scan PGP keyring for non-friend peers who have signed us */ + if (rsPeers) + { + std::list pgpIds; + rsPeers->getGPGAllList(pgpIds); + + bool addedNew = false; + for (const RsPgpId &pgpId : pgpIds) + { + RsPeerDetails details; + if (!rsPeers->getGPGDetails(pgpId, details)) + continue; + + if (!details.hasSignedMe || details.accept_connection) + continue; + + QString pgpStr = QString::fromStdString(pgpId.toStdString()); + if (mRejectedPeers.contains(pgpStr)) + continue; + + AttemptEntry entry; + entry.pgpId = pgpStr; + entry.sslCn = QString::fromUtf8(details.name.c_str()); + entry.timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch(); + + RsPeerId sslId; + std::list sslIds; + if (rsPeers->getAssociatedSSLIds(pgpId, sslIds) && !sslIds.empty()) + sslId = sslIds.front(); + entry.sslId = QString::fromStdString(sslId.toStdString()); + + if (!mStoredAttempts.contains(entry)) + { + mStoredAttempts.append(entry); + addSecurityItem(entry); + addedNew = true; + } + } + + if (addedNew) + saveStoredRequests(); + } + + updateCount(); +} + +void FriendRequestsDialog::saveStoredRequests() +{ + QVariantList list; + for (const AttemptEntry &entry : mStoredAttempts) + { + QVariantMap map; + map["pgpId"] = entry.pgpId; + map["sslId"] = entry.sslId; + map["sslCn"] = entry.sslCn; + map["locator"] = entry.locator; + map["timestamp"] = entry.timestamp; + list.append(map); + } + + Settings->beginGroup("FriendRequests"); + Settings->setValue("StoredAttempts", list); + Settings->endGroup(); +} + +void FriendRequestsDialog::handleAuthSslEvent(std::shared_ptr event) +{ + RsQThreadUtils::postToObject([=]() + { + const RsAuthSslConnectionAutenticationEvent *pe = + dynamic_cast(event.get()); + + if (!pe || pe->mErrorCode != RsAuthSslError::NOT_A_FRIEND) + return; + + QString pgpStr = QString::fromStdString(pe->mPgpId.toStdString()); + QString sslStr = QString::fromStdString(pe->mSslId.toStdString()); + + QString rejKey = pgpStr.isEmpty() ? sslStr : pgpStr; + if (mRejectedPeers.contains(rejKey)) + return; + + if (!pgpStr.isEmpty() && rsPeers && rsPeers->isPgpFriend(pe->mPgpId)) + return; + + AttemptEntry entry; + entry.pgpId = pgpStr; + entry.sslId = sslStr; + entry.sslCn = QString::fromUtf8(pe->mSslCn.c_str()); + entry.locator = QString::fromStdString(pe->mLocator.toString()); + entry.timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch(); + + int idx = mStoredAttempts.indexOf(entry); + if (idx >= 0) + { + /* Update existing entry data */ + mStoredAttempts[idx].timestamp = entry.timestamp; + if (!entry.sslCn.isEmpty()) + mStoredAttempts[idx].sslCn = entry.sslCn; + if (!entry.locator.isEmpty()) + mStoredAttempts[idx].locator = entry.locator; + + saveStoredRequests(); + } + else + { + mStoredAttempts.append(entry); + saveStoredRequests(); + addSecurityItem(entry); + updateCount(); + } + }, this); +} + +void FriendRequestsDialog::handleFriendListEvent(std::shared_ptr event) +{ + RsQThreadUtils::postToObject([=]() + { + auto fe = dynamic_cast(event.get()); + if (!fe || !rsPeers) + return; + + bool changed = false; + QList itemsToRemove; + + for (auto it = mItemMap.begin(); it != mItemMap.end(); ++it) + { + const AttemptEntry &entry = it.value(); + if (!entry.pgpId.isEmpty() && rsPeers->isPgpFriend(RsPgpId(entry.pgpId.toStdString()))) + { + itemsToRemove.append(it.key()); + mStoredAttempts.removeAll(entry); + changed = true; + } + } + + for (FeedItem *item : itemsToRemove) + { + mFeedWidget->removeFeedItem(item); + item->close(); + } + + if (changed) + { + saveStoredRequests(); + updateCount(); + } + }, this); +} + +void FriendRequestsDialog::addSecurityItem(const AttemptEntry &entry) +{ + RsPgpId gpgId(entry.pgpId.toStdString()); + RsPeerId sslId(entry.sslId.toStdString()); + + SecurityItem *item = new SecurityItem( + this, FRIENDREQUESTS_FEEDID, gpgId, sslId, entry.sslCn.toStdString(), + entry.locator.toStdString(), + RsFeedTypeFlags::RS_FEED_ITEM_SEC_CONNECT_ATTEMPT, false); + + item->setAttribute(Qt::WA_DeleteOnClose, true); + connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(onItemDestroyed(QObject*))); + + mItemMap.insert(item, entry); + + QDateTime dt = QDateTime::fromMSecsSinceEpoch(entry.timestamp); + mFeedWidget->addFeedItem(item, FEED_TREEWIDGET_SORTROLE, dt); +} + +void FriendRequestsDialog::onItemDestroyed(QObject *obj) +{ + mItemMap.remove(static_cast(obj)); +} + +void FriendRequestsDialog::clearAll() +{ + for (const AttemptEntry &entry : mStoredAttempts) + { + QString rejKey = entry.pgpId.isEmpty() ? entry.sslId : entry.pgpId; + if (!rejKey.isEmpty()) + mRejectedPeers.insert(rejKey); + } + + Settings->beginGroup("FriendRequests"); + Settings->setValue("Rejected", QStringList(mRejectedPeers.values())); + Settings->endGroup(); + + mStoredAttempts.clear(); + saveStoredRequests(); + + mFeedWidget->clear(); + updateCount(); +} + +int FriendRequestsDialog::pendingRequestCount() const +{ + return mFeedWidget->feedItemCount(); +} + +void FriendRequestsDialog::updateCount() +{ + emit requestCountChanged(mFeedWidget->feedItemCount()); +} + +/* FeedHolder Interface Implementation */ + +QScrollArea *FriendRequestsDialog::getScrollArea() +{ + return nullptr; +} + +void FriendRequestsDialog::deleteFeedItem(FeedItem *item, uint32_t /*type*/) +{ + if (!item) + return; + + if (mItemMap.contains(item)) + { + AttemptEntry entry = mItemMap.value(item); + QString rejKey = entry.pgpId.isEmpty() ? entry.sslId : entry.pgpId; + if (!rejKey.isEmpty()) + { + mRejectedPeers.insert(rejKey); + Settings->beginGroup("FriendRequests"); + Settings->setValue("Rejected", QStringList(mRejectedPeers.values())); + Settings->endGroup(); + } + + mStoredAttempts.removeAll(entry); + saveStoredRequests(); + } + + mFeedWidget->removeFeedItem(item); + item->close(); +} + +void FriendRequestsDialog::openChat(const RsPeerId &peerId) +{ + ChatDialog::chatFriend(ChatId(peerId)); +} + +void FriendRequestsDialog::openComments(uint32_t /*type*/, const RsGxsGroupId &/*groupId*/, const QVector &/*msg_versions*/, const RsGxsMessageId &/*msgId*/, const QString &/*title*/) +{ + /* Not applicable for friend requests */ +} diff --git a/retroshare-gui/src/gui/FriendRequestsDialog.h b/retroshare-gui/src/gui/FriendRequestsDialog.h new file mode 100644 index 000000000..833f46ede --- /dev/null +++ b/retroshare-gui/src/gui/FriendRequestsDialog.h @@ -0,0 +1,98 @@ +/******************************************************************************* + * gui/FriendRequestsDialog.h * + * * + * Copyright (C) 2026 Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#ifndef _FRIENDREQUESTSDIALOG_H +#define _FRIENDREQUESTSDIALOG_H + +#include +#include +#include +#include +#include + +#include +#include +#include "gui/feeds/FeedHolder.h" + +class RSFeedWidget; +class FeedItem; +class QPushButton; + +#define FRIENDREQUESTS_FEEDID 0x0020 + +struct AttemptEntry +{ + QString pgpId; + QString sslId; + QString sslCn; + QString locator; + qint64 timestamp; + + bool operator==(const AttemptEntry &other) const + { + if (!pgpId.isEmpty() && !other.pgpId.isEmpty()) + return pgpId == other.pgpId; + return sslId == other.sslId; + } +}; + +class FriendRequestsDialog : public QWidget, public FeedHolder +{ + Q_OBJECT + +public: + FriendRequestsDialog(QWidget *parent = 0); + ~FriendRequestsDialog() override; + + int pendingRequestCount() const; + + /* FeedHolder Interface */ + QScrollArea *getScrollArea() override; + void deleteFeedItem(FeedItem *item, uint32_t type) override; + void openChat(const RsPeerId &peerId) override; + void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector &msg_versions, const RsGxsMessageId &msgId, const QString &title) override; + +signals: + void requestCountChanged(int count); + +private slots: + void clearAll(); + void onItemDestroyed(QObject *obj); + +private: + void loadStoredRequests(); + void saveStoredRequests(); + void handleAuthSslEvent(std::shared_ptr event); + void handleFriendListEvent(std::shared_ptr event); + void addSecurityItem(const AttemptEntry &entry); + void updateCount(); + + RSFeedWidget *mFeedWidget; + QPushButton *mClearAllButton; + + QSet mRejectedPeers; + QList mStoredAttempts; + QMap mItemMap; + + RsEventsHandlerId_t mAuthEventHandlerId; + RsEventsHandlerId_t mFriendEventHandlerId; +}; + +#endif diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index 785bbe4d9..1be139f52 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -50,12 +50,14 @@ #include "gui/FriendServerControl.h" #endif #include "gui/Identity/IdDialog.h" +#include "gui/FriendRequestsDialog.h" /* Images for Newsfeed icons */ //#define IMAGE_NEWSFEED "" //#define IMAGE_NEWSFEED_NEW ":/images/message-state-new.png" #define IMAGE_NETWORK2 ":/icons/png/netgraph2.png" #define IMAGE_PEERS ":/icons/png/digital-key.png" #define IMAGE_IDENTITY ":/images/identity/identities_32.png" +#define IMAGE_FRIENDREQUESTS ":/images/user/user_request48.png" /****** * #define FRIENDS_DEBUG 1 @@ -130,14 +132,18 @@ FriendsDialog::FriendsDialog(QWidget *parent) : MainPage(parent) if(RsAccounts::isTorAuto()) ui.tabWidget->addTab(friendServerControl = new FriendServerControl(),QIcon(IMAGE_PEERS), tr("Friend Server")); #endif + ui.tabWidget->addTab(friendRequestsDialog = new FriendRequestsDialog(),QIcon(IMAGE_FRIENDREQUESTS), tr("Friend Requests")); ui.tabWidget->addTab(networkView = new NetworkView(),QIcon(IMAGE_NETWORK2), tr("Network graph")); ui.tabWidget->addTab(networkDialog = new NetworkDialog(),QIcon(IMAGE_PEERS), tr("Keyring")); + connect(friendRequestsDialog, SIGNAL(requestCountChanged(int)), this, SLOT(updateFriendRequestsTabCount(int))); + ui.tabWidget->hideCloseButton(0); ui.tabWidget->hideCloseButton(1); ui.tabWidget->hideCloseButton(2); ui.tabWidget->hideCloseButton(3); ui.tabWidget->hideCloseButton(4); + ui.tabWidget->hideCloseButton(5); /* Set initial size the splitter */ ui.splitter->setStretchFactor(0, 0); @@ -333,3 +339,15 @@ void FriendsDialog::statusmessage() friendsDialog->ui.tabWidget->setCurrentWidget(friendsDialog->ui.groupChatTab); friendsDialog->ui.chatWidget->focusDialog(); } + +void FriendsDialog::updateFriendRequestsTabCount(int count) +{ + int tabIndex = ui.tabWidget->indexOf(friendRequestsDialog); + if (tabIndex < 0) + return; + + if (count > 0) + ui.tabWidget->setTabText(tabIndex, tr("Friend Requests (%1)").arg(count)); + else + ui.tabWidget->setTabText(tabIndex, tr("Friend Requests")); +} diff --git a/retroshare-gui/src/gui/FriendsDialog.h b/retroshare-gui/src/gui/FriendsDialog.h index f6ec0e0a8..b6c0ca5e4 100644 --- a/retroshare-gui/src/gui/FriendsDialog.h +++ b/retroshare-gui/src/gui/FriendsDialog.h @@ -31,6 +31,7 @@ class NetworkView; class IdDialog; class CirclesDialog; class FriendServerControl; +class FriendRequestsDialog; class FriendsDialog : public MainPage { @@ -66,6 +67,7 @@ public: NetworkDialog *networkDialog ; NetworkView *networkView ; FriendServerControl *friendServerControl ; + FriendRequestsDialog *friendRequestsDialog ; IdDialog *idDialog; @@ -79,6 +81,7 @@ private slots: void loadmypersonalstatus(); void clearChatNotify(); + void updateFriendRequestsTabCount(int count); //void newsFeedChanged(int count); diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index cdce55926..f8913e2ee 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -387,6 +387,7 @@ HEADERS += rshare.h \ gui/AboutWidget.h \ gui/NetworkView.h \ gui/FriendsDialog.h \ + gui/FriendRequestsDialog.h \ gui/ServicePermissionDialog.h \ gui/RemoteDirModel.h \ gui/RetroShareLink.h \ @@ -763,6 +764,7 @@ SOURCES += main.cpp \ gui/MainWindow.cpp \ gui/NetworkView.cpp \ gui/FriendsDialog.cpp \ + gui/FriendRequestsDialog.cpp \ gui/ServicePermissionDialog.cpp \ gui/RemoteDirModel.cpp \ gui/RsAutoUpdatePage.cpp \ From 0b89f5c4ce89d50f4582e7269ba7aadec713d97d Mon Sep 17 00:00:00 2001 From: haroon0x Date: Sun, 17 May 2026 13:18:11 +0530 Subject: [PATCH 2/2] Fix friend request self filtering --- .../src/gui/FriendRequestsDialog.cpp | 91 +++++++++++++++---- retroshare-gui/src/gui/FriendRequestsDialog.h | 2 + retroshare-gui/src/gui/FriendsDialog.cpp | 8 +- 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/retroshare-gui/src/gui/FriendRequestsDialog.cpp b/retroshare-gui/src/gui/FriendRequestsDialog.cpp index c4ffc0bc0..44b61f36d 100644 --- a/retroshare-gui/src/gui/FriendRequestsDialog.cpp +++ b/retroshare-gui/src/gui/FriendRequestsDialog.cpp @@ -71,7 +71,6 @@ FriendRequestsDialog::FriendRequestsDialog(QWidget *parent) /* Feed widget */ mFeedWidget = new RSFeedWidget(this); mFeedWidget->setPlaceholderText(tr("No friend requests")); - mFeedWidget->enableRemove(true); mFeedWidget->setSortRole(FEED_TREEWIDGET_SORTROLE, Qt::DescendingOrder); vLayout->addWidget(mFeedWidget); @@ -102,6 +101,55 @@ FriendRequestsDialog::~FriendRequestsDialog() rsEvents->unregisterEventsHandler(mFriendEventHandlerId); } +QString FriendRequestsDialog::requestKey(const AttemptEntry &entry) const +{ + return entry.pgpId.isEmpty() ? entry.sslId : entry.pgpId; +} + +bool FriendRequestsDialog::shouldIgnoreRequest(const AttemptEntry &entry) const +{ + if (!rsPeers) + return true; + + RsPgpId pgpId(entry.pgpId.toStdString()); + RsPeerId sslId(entry.sslId.toStdString()); + + if (!entry.pgpId.isEmpty()) + { + if (pgpId == rsPeers->getGPGOwnId() || rsPeers->isPgpFriend(pgpId)) + return true; + + RsPeerDetails gpgDetails; + if (rsPeers->getGPGDetails(pgpId, gpgDetails) && gpgDetails.accept_connection) + return true; + } + + if (!entry.sslId.isEmpty()) + { + if (sslId == rsPeers->getOwnId() || rsPeers->isFriend(sslId)) + return true; + + std::list ownSslIds; + if (rsPeers->getAssociatedSSLIds(rsPeers->getGPGOwnId(), ownSslIds)) + { + for (const RsPeerId &ownSslId : ownSslIds) + if (sslId == ownSslId) + return true; + } + + RsPeerDetails sslDetails; + if (rsPeers->getPeerDetails(sslId, sslDetails)) + { + if (sslDetails.id == rsPeers->getOwnId() || + sslDetails.gpg_id == rsPeers->getGPGOwnId() || + sslDetails.accept_connection) + return true; + } + } + + return false; +} + void FriendRequestsDialog::loadStoredRequests() { Settings->beginGroup("FriendRequests"); @@ -112,6 +160,7 @@ void FriendRequestsDialog::loadStoredRequests() for (const QString &s : rejected) mRejectedPeers.insert(s); + bool changedStored = false; for (const QVariant &v : list) { QVariantMap map = v.toMap(); @@ -123,13 +172,18 @@ void FriendRequestsDialog::loadStoredRequests() entry.timestamp = map["timestamp"].toLongLong(); /* Ignore if rejected */ - QString rejKey = entry.pgpId.isEmpty() ? entry.sslId : entry.pgpId; - if (mRejectedPeers.contains(rejKey)) + if (mRejectedPeers.contains(requestKey(entry))) + { + changedStored = true; continue; + } - /* Ignore if already a friend */ - if (!entry.pgpId.isEmpty() && rsPeers && rsPeers->isPgpFriend(RsPgpId(entry.pgpId.toStdString()))) + /* Ignore own locations and accepted peers that became stale while stored */ + if (shouldIgnoreRequest(entry)) + { + changedStored = true; continue; + } /* Ensure no duplicates */ if (!mStoredAttempts.contains(entry)) @@ -137,6 +191,8 @@ void FriendRequestsDialog::loadStoredRequests() mStoredAttempts.append(entry); addSecurityItem(entry); } + else + changedStored = true; } /* Scan PGP keyring for non-friend peers who have signed us */ @@ -152,7 +208,7 @@ void FriendRequestsDialog::loadStoredRequests() if (!rsPeers->getGPGDetails(pgpId, details)) continue; - if (!details.hasSignedMe || details.accept_connection) + if (pgpId == rsPeers->getGPGOwnId() || !details.hasSignedMe || details.accept_connection) continue; QString pgpStr = QString::fromStdString(pgpId.toStdString()); @@ -170,6 +226,9 @@ void FriendRequestsDialog::loadStoredRequests() sslId = sslIds.front(); entry.sslId = QString::fromStdString(sslId.toStdString()); + if (shouldIgnoreRequest(entry)) + continue; + if (!mStoredAttempts.contains(entry)) { mStoredAttempts.append(entry); @@ -178,9 +237,11 @@ void FriendRequestsDialog::loadStoredRequests() } } - if (addedNew) + if (addedNew || changedStored) saveStoredRequests(); } + else if (changedStored) + saveStoredRequests(); updateCount(); } @@ -217,13 +278,6 @@ void FriendRequestsDialog::handleAuthSslEvent(std::shared_ptr eve QString pgpStr = QString::fromStdString(pe->mPgpId.toStdString()); QString sslStr = QString::fromStdString(pe->mSslId.toStdString()); - QString rejKey = pgpStr.isEmpty() ? sslStr : pgpStr; - if (mRejectedPeers.contains(rejKey)) - return; - - if (!pgpStr.isEmpty() && rsPeers && rsPeers->isPgpFriend(pe->mPgpId)) - return; - AttemptEntry entry; entry.pgpId = pgpStr; entry.sslId = sslStr; @@ -231,6 +285,9 @@ void FriendRequestsDialog::handleAuthSslEvent(std::shared_ptr eve entry.locator = QString::fromStdString(pe->mLocator.toString()); entry.timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch(); + if (mRejectedPeers.contains(requestKey(entry)) || shouldIgnoreRequest(entry)) + return; + int idx = mStoredAttempts.indexOf(entry); if (idx >= 0) { @@ -267,7 +324,7 @@ void FriendRequestsDialog::handleFriendListEvent(std::shared_ptr for (auto it = mItemMap.begin(); it != mItemMap.end(); ++it) { const AttemptEntry &entry = it.value(); - if (!entry.pgpId.isEmpty() && rsPeers->isPgpFriend(RsPgpId(entry.pgpId.toStdString()))) + if (shouldIgnoreRequest(entry)) { itemsToRemove.append(it.key()); mStoredAttempts.removeAll(entry); @@ -317,7 +374,7 @@ void FriendRequestsDialog::clearAll() { for (const AttemptEntry &entry : mStoredAttempts) { - QString rejKey = entry.pgpId.isEmpty() ? entry.sslId : entry.pgpId; + QString rejKey = requestKey(entry); if (!rejKey.isEmpty()) mRejectedPeers.insert(rejKey); } @@ -358,7 +415,7 @@ void FriendRequestsDialog::deleteFeedItem(FeedItem *item, uint32_t /*type*/) if (mItemMap.contains(item)) { AttemptEntry entry = mItemMap.value(item); - QString rejKey = entry.pgpId.isEmpty() ? entry.sslId : entry.pgpId; + QString rejKey = requestKey(entry); if (!rejKey.isEmpty()) { mRejectedPeers.insert(rejKey); diff --git a/retroshare-gui/src/gui/FriendRequestsDialog.h b/retroshare-gui/src/gui/FriendRequestsDialog.h index 833f46ede..3641d96f9 100644 --- a/retroshare-gui/src/gui/FriendRequestsDialog.h +++ b/retroshare-gui/src/gui/FriendRequestsDialog.h @@ -82,6 +82,8 @@ private: void handleAuthSslEvent(std::shared_ptr event); void handleFriendListEvent(std::shared_ptr event); void addSecurityItem(const AttemptEntry &entry); + bool shouldIgnoreRequest(const AttemptEntry &entry) const; + QString requestKey(const AttemptEntry &entry) const; void updateCount(); RSFeedWidget *mFeedWidget; diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index 1be139f52..3e9006a80 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -138,12 +138,8 @@ FriendsDialog::FriendsDialog(QWidget *parent) : MainPage(parent) connect(friendRequestsDialog, SIGNAL(requestCountChanged(int)), this, SLOT(updateFriendRequestsTabCount(int))); - ui.tabWidget->hideCloseButton(0); - ui.tabWidget->hideCloseButton(1); - ui.tabWidget->hideCloseButton(2); - ui.tabWidget->hideCloseButton(3); - ui.tabWidget->hideCloseButton(4); - ui.tabWidget->hideCloseButton(5); + for (int i = 0; i < ui.tabWidget->count(); ++i) + ui.tabWidget->hideCloseButton(i); /* Set initial size the splitter */ ui.splitter->setStretchFactor(0, 0);