From 2ca36f59574c3bb31bd7b096f7d435493afe325d Mon Sep 17 00:00:00 2001 From: David Bears Date: Thu, 2 Jan 2025 22:27:43 -0500 Subject: [PATCH 1/4] Fix port settings for manual I2P --- retroshare-gui/src/gui/settings/ServerPage.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index adb1d655c..be2404bc8 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -228,6 +228,7 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) connect(ui.hiddenpage_proxyPort_tor, SIGNAL(editingFinished()),this,SLOT(saveAddresses())); connect(ui.hiddenpage_proxyAddress_i2p, SIGNAL(editingFinished()),this,SLOT(saveAddresses())); connect(ui.hiddenpage_proxyPort_i2p, SIGNAL(editingFinished()),this,SLOT(saveAddresses())); + connect(ui.hiddenpage_localPort, SIGNAL(editingFinished()),this,SLOT(saveAddresses())); connect(ui.totalDownloadRate,SIGNAL(valueChanged(int)),this,SLOT(saveRates())); connect(ui.totalUploadRate, SIGNAL(valueChanged(int)),this,SLOT(saveRates())); @@ -1139,18 +1140,18 @@ void ServerPage::loadHiddenNode() ui.iconlabel_ext->hide(); ui.textlabel_ext->hide(); ui.extPortLabel->hide(); - + ui.ipAddressLabel->hide(); ui.cleanKnownIPs_PB->hide(); - + ui.ipAddressList->hide(); ui.allowIpDeterminationCB->hide(); ui.IPServersLV->hide(); - + ui.textlabel_hiddenMode->show(); ui.iconlabel_hiddenMode->show() ; ui.iconlabel_hiddenMode->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/ledon1.png")); - + // CHANGE OPTIONS ON whileBlocking(ui.discComboBox)->removeItem(3); whileBlocking(ui.discComboBox)->removeItem(2); @@ -1731,8 +1732,9 @@ void ServerPage::saveSam() new_proxyaddr = ui.hiddenpage_proxyAddress_i2p -> text().toStdString(); new_proxyport = ui.hiddenpage_proxyPort_i2p -> value(); - // SAMv3 has no proxy port, everything goes through the SAM port. - if ((new_proxyaddr != orig_proxyaddr) /* || (new_proxyport != orig_proxyport) */) { + // SAMv3 has no proxy port, everything goes through the SAM port. + // Still need to check the proxyport for manual i2p + if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) { rsPeers->setProxyServer(RS_HIDDEN_TYPE_I2P, new_proxyaddr, new_proxyport); } } From 0759359e06de756a70ac9c963480d700a69d5a79 Mon Sep 17 00:00:00 2001 From: David Bears Date: Thu, 2 Jan 2025 22:38:46 -0500 Subject: [PATCH 2/4] Fix JSON API token removal --- .../src/gui/settings/JsonApiPage.cc | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/retroshare-gui/src/gui/settings/JsonApiPage.cc b/retroshare-gui/src/gui/settings/JsonApiPage.cc index 2b7f25d80..ace092e0c 100644 --- a/retroshare-gui/src/gui/settings/JsonApiPage.cc +++ b/retroshare-gui/src/gui/settings/JsonApiPage.cc @@ -232,23 +232,23 @@ void JsonApiPage::addTokenClicked() whileBlocking(ui.tokensListView)->setModel(new QStringListModel(newTk)); } -void JsonApiPage::removeTokenClicked() -{ - QString token(ui.tokenLineEdit->text()); - rsJsonApi->revokeAuthToken(token.toStdString()); - - QStringList newTk; - - for(const auto& it : rsJsonApi->getAuthorizedTokens()) - newTk.push_back( - QString::fromStdString(it.first) + ":" + - QString::fromStdString(it.second) ); - - whileBlocking(ui.tokensListView)->setModel(new QStringListModel(Settings->getJsonApiAuthTokens()) ); -} - +void JsonApiPage::removeTokenClicked() +{ + QString token(ui.tokenLineEdit->text()); + std::string tokenStr = token.toStdString(); + rsJsonApi->revokeAuthToken(tokenStr.substr(0, tokenStr.find_first_of(":"))); + + QStringList newTk; + + for(const auto& it : rsJsonApi->getAuthorizedTokens()) + newTk.push_back( + QString::fromStdString(it.first) + ":" + + QString::fromStdString(it.second) ); + + whileBlocking(ui.tokensListView)->setModel(new QStringListModel(Settings->getJsonApiAuthTokens()) ); +} + void JsonApiPage::tokenClicked(const QModelIndex& index) { ui.tokenLineEdit->setText(ui.tokensListView->model()->data(index).toString()); } - From 99053597a909e3fc43faf4d143dba611025ddb33 Mon Sep 17 00:00:00 2001 From: David Bears Date: Fri, 3 Jan 2025 15:03:31 -0500 Subject: [PATCH 3/4] allow voting on own identities --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 134 +++++++++---------- 1 file changed, 65 insertions(+), 69 deletions(-) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 5afac35d3..032acaa2d 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -50,7 +50,7 @@ #include "util/rsdebug.h" #include "retroshare/rsgxsflags.h" -#include "retroshare/rsmsgs.h" +#include "retroshare/rsmsgs.h" #include "retroshare/rspeers.h" #include "retroshare/rsservicecontrol.h" @@ -167,7 +167,7 @@ IdDialog::IdDialog(QWidget *parent) // This is used to grab the broadcast of changes from p3GxsCircles, which is discarded by the current dialog, since it expects data for p3Identity only. //mCirclesBroadcastBase = new RsGxsUpdateBroadcastBase(rsGxsCircles, this); //connect(mCirclesBroadcastBase, SIGNAL(fillDisplay(bool)), this, SLOT(updateCirclesDisplay(bool))); - + ownItem = new QTreeWidgetItem(); ownItem->setText(RSID_COL_NICKNAME, tr("My own identities")); ownItem->setFont(RSID_COL_NICKNAME, ui->idTreeWidget->font()); @@ -253,7 +253,7 @@ IdDialog::IdDialog(QWidget *parent) connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); connect(ui->ownOpinion_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(modifyReputation())); - + connect(ui->inviteButton, SIGNAL(clicked()), this, SLOT(sendInvite())); connect(ui->editButton, SIGNAL(clicked()), this, SLOT(editIdentity())); @@ -269,7 +269,7 @@ IdDialog::IdDialog(QWidget *parent) /* Initialize splitter */ ui->mainSplitter->setStretchFactor(0, 0); ui->mainSplitter->setStretchFactor(1, 1); - + clearPerson(); /* Add filter types */ @@ -327,18 +327,18 @@ IdDialog::IdDialog(QWidget *parent) idTWHAction->setData(RSID_FILTER_BANNED); connect(idTWHAction, SIGNAL(toggled(bool)), this, SLOT(filterToggled(bool))); idTWHMenu->addAction(idTWHAction); - + QAction *CreateIDAction = new QAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/person.png"),tr("Create new Identity"), this); connect(CreateIDAction, SIGNAL(triggered()), this, SLOT(addIdentity())); - + QAction *CreateCircleAction = new QAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/circles.png"),tr("Create new circle"), this); connect(CreateCircleAction, SIGNAL(triggered()), this, SLOT(createExternalCircle())); - + QMenu *menu = new QMenu(); menu->addAction(CreateIDAction); menu->addAction(CreateCircleAction); ui->toolButton_New->setMenu(menu); - + /* Add filter actions */ QTreeWidgetItem *headerItem = ui->idTreeWidget->headerItem(); QString headerText = headerItem->text(RSID_COL_NICKNAME); @@ -361,14 +361,14 @@ IdDialog::IdDialog(QWidget *parent) ui->idTreeWidget->setColumnHidden(RSID_COL_IDTYPE, true); ui->idTreeWidget->setColumnHidden(RSID_COL_KEYID, true); - + /* Set initial column width */ int fontWidth = QFontMetricsF(ui->idTreeWidget->font()).width("W"); ui->idTreeWidget->setColumnWidth(RSID_COL_NICKNAME, 14 * fontWidth); ui->idTreeWidget->setColumnWidth(RSID_COL_KEYID, 20 * fontWidth); ui->idTreeWidget->setColumnWidth(RSID_COL_IDTYPE, 18 * fontWidth); ui->idTreeWidget->setColumnWidth(RSID_COL_VOTES, 2 * fontWidth); - + ui->idTreeWidget->setItemDelegate(new RSElidedItemDelegate()); ui->idTreeWidget->setItemDelegateForColumn( RSID_COL_NICKNAME, @@ -408,7 +408,7 @@ IdDialog::IdDialog(QWidget *parent) processSettings(true); // circles stuff - + //connect(ui->treeWidget_membership, SIGNAL(itemSelectionChanged()), this, SLOT(circle_selected())); connect(ui->treeWidget_membership, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CircleListCustomPopupMenu(QPoint))); connect(ui->autoBanIdentities_CB, SIGNAL(toggled(bool)), this, SLOT(toggleAutoBanIdentities(bool))); @@ -516,10 +516,10 @@ void IdDialog::updateCirclesDisplay() { if(RsAutoUpdatePage::eventsLocked()) return ; - + if(!isVisible()) return ; - + #ifdef ID_DEBUG std::cerr << "!!Updating circles display!" << std::endl; #endif @@ -929,16 +929,16 @@ void IdDialog::loadCircles(const std::list& groupInfo) bool IdDialog::getItemCircleId(QTreeWidgetItem *item,RsGxsCircleId& id) { -#ifdef CIRCLE_MEMBERSHIP_CATEGORIES +#ifdef CIRCLE_MEMBERSHIP_CATEGORIES if ((!item) || (!item->parent())) return false; - + QString coltext = (item->parent()->parent())? (item->parent()->data(CIRCLEGROUP_CIRCLE_COL_GROUPID,Qt::UserRole).toString()) : (item->data(CIRCLEGROUP_CIRCLE_COL_GROUPID,Qt::UserRole).toString()); id = RsGxsCircleId( coltext.toStdString()) ; #else if(!item) return false; - + QString coltext = (item->parent())? (item->parent()->data(CIRCLEGROUP_CIRCLE_COL_GROUPID,Qt::UserRole).toString()) : (item->data(CIRCLEGROUP_CIRCLE_COL_GROUPID,Qt::UserRole).toString()); id = RsGxsCircleId( coltext.toStdString()) ; #endif @@ -967,19 +967,19 @@ void IdDialog::createExternalCircle() void IdDialog::showEditExistingCircle() { RsGxsCircleId id ; - + if(!getItemCircleId(ui->treeWidget_membership->currentItem(),id)) return ; - + uint32_t subscribe_flags = ui->treeWidget_membership->currentItem()->data(CIRCLEGROUP_CIRCLE_COL_GROUPFLAGS, Qt::UserRole).toUInt(); - + CreateCircleDialog dlg; - + dlg.editExistingId(RsGxsGroupId(id),true,!(subscribe_flags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN)) ; dlg.exec(); } -void IdDialog::grantCircleMembership() +void IdDialog::grantCircleMembership() { RsGxsCircleId circle_id ; @@ -996,7 +996,7 @@ void IdDialog::grantCircleMembership() }); } -void IdDialog::revokeCircleMembership() +void IdDialog::revokeCircleMembership() { RsGxsCircleId circle_id ; @@ -1025,22 +1025,22 @@ void IdDialog::revokeCircleMembership() }); } -void IdDialog::acceptCircleSubscription() +void IdDialog::acceptCircleSubscription() { RsGxsCircleId circle_id ; - + if(!getItemCircleId(ui->treeWidget_membership->currentItem(),circle_id)) return; RsGxsId own_id(qobject_cast(sender())->data().toString().toStdString()); - + rsGxsCircles->requestCircleMembership(own_id,circle_id) ; } -void IdDialog::cancelCircleSubscription() -{ +void IdDialog::cancelCircleSubscription() +{ RsGxsCircleId circle_id ; - + if(!getItemCircleId(ui->treeWidget_membership->currentItem(),circle_id)) return; @@ -1048,14 +1048,14 @@ void IdDialog::cancelCircleSubscription() rsGxsCircles->cancelCircleMembership(own_id,circle_id) ; } - + void IdDialog::CircleListCustomPopupMenu( QPoint ) { QMenu contextMnu( this ); RsGxsCircleId circle_id ; QTreeWidgetItem *item = ui->treeWidget_membership->currentItem(); - + if(!getItemCircleId(item,circle_id)) return ; @@ -1063,7 +1063,7 @@ void IdDialog::CircleListCustomPopupMenu( QPoint ) RsGxsId item_id(item->data(CIRCLEGROUP_CIRCLE_COL_GROUPID,Qt::UserRole).toString().toStdString()); bool is_circle ; bool am_I_circle_admin = false ; - + if(item_id == RsGxsId(circle_id)) // is it a circle? { uint32_t group_flags = item->data(CIRCLEGROUP_CIRCLE_COL_GROUPFLAGS, Qt::UserRole).toUInt(); @@ -1082,7 +1082,7 @@ void IdDialog::CircleListCustomPopupMenu( QPoint ) #ifdef CIRCLE_MEMBERSHIP_CATEGORIES } #endif - + #ifdef ID_DEBUG std::cerr << " Item is a circle item. Adding Edit/Details menu entry." << std::endl; #endif @@ -1090,7 +1090,7 @@ void IdDialog::CircleListCustomPopupMenu( QPoint ) contextMnu.addSeparator() ; } - else + else { current_gxs_id = RsGxsId(item_id); is_circle =false ; @@ -1105,9 +1105,9 @@ void IdDialog::CircleListCustomPopupMenu( QPoint ) std::cerr << " Item is a GxsId item. Requesting flags/group id from parent: " << circle_id << std::endl; #endif } - + RsGxsCircleDetails details ; - + if(!rsGxsCircles->getCircleDetails(circle_id,details))// grab real circle ID from parent. Make sure circle id is used correctly afterwards! { std::cerr << " (EE) cannot get circle info for ID " << circle_id << ". Not in cache?" << std::endl; @@ -1144,7 +1144,7 @@ void IdDialog::CircleListCustomPopupMenu( QPoint ) ids[REMOVE].push_back(*it) ; else ids[CANCEL].push_back(*it) ; - else + else if(subscribe_flags & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST) ids[ACCEPT].push_back(*it) ; else @@ -1205,17 +1205,17 @@ void IdDialog::CircleListCustomPopupMenu( QPoint ) contextMnu.addMenu(menu) ; } } - + if(!is_circle && am_I_circle_admin) // I am circle admin. I can therefore revoke/accept membership { std::map::const_iterator it = details.mSubscriptionFlags.find(current_gxs_id) ; - + if(!current_gxs_id.isNull() && it != details.mSubscriptionFlags.end()) { contextMnu.addSeparator() ; if(it->second & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST) - { + { QAction *action = new QAction(tr("Revoke this member"),this) ; action->setData(QString::fromStdString(current_gxs_id.toStdString())); QObject::connect(action,SIGNAL(triggered()), this, SLOT(revokeCircleMembership())); @@ -1260,7 +1260,7 @@ static QString getHumanReadableDuration(uint32_t seconds) return QString(QObject::tr("%1 hours ago")).arg(seconds/3600) ; else if(seconds < 2*24*3600) return QString(QObject::tr("%1 day ago")).arg(seconds/86400) ; - else + else return QString(QObject::tr("%1 days ago")).arg(seconds/86400) ; } @@ -1292,7 +1292,7 @@ void IdDialog::processSettings(bool load) // state of splitter Settings->setValue("splitter", ui->mainSplitter->saveState()); - + //save expanding Settings->setValue("ExpandAll", allItem->isExpanded()); Settings->setValue("ExpandContacts", contactsItem->isExpanded()); @@ -1486,13 +1486,13 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item, rsPeers->getGPGDetails(data.mPgpId, details); item->setText(RSID_COL_IDTYPE, QString::fromUtf8(details.name.c_str())); item->setToolTip(RSID_COL_IDTYPE,"Verified signature from node "+QString::fromStdString(data.mPgpId.toStdString())) ; - - + + QString tooltip = tr("Node name:")+" " + QString::fromUtf8(details.name.c_str()) + "\n"; tooltip += tr("Node Id :")+" " + QString::fromStdString(data.mPgpId.toStdString()) ; item->setToolTip(RSID_COL_KEYID,tooltip) ; } - else + else { QString txt = tr("[Unknown node]"); item->setText(RSID_COL_IDTYPE, txt); @@ -1547,13 +1547,13 @@ void IdDialog::loadIdentities(const std::map& ids_set RsPgpId ownPgpId = rsPeers->getGPGOwnId(); - // Update existing and remove not existing items + // Update existing and remove not existing items // Also remove items that do not have the correct parent QTreeWidgetItemIterator itemIterator(ui->idTreeWidget); QTreeWidgetItem *item = NULL; - while ((item = *itemIterator) != NULL) + while ((item = *itemIterator) != NULL) { ++itemIterator; auto it = ids_set.find(RsGxsGroupId(item->text(RSID_COL_KEYID).toStdString())) ; @@ -1601,11 +1601,11 @@ void IdDialog::loadIdentities(const std::map& ids_set } } - + /* count items */ int itemCount = contactsItem->childCount() + allItem->childCount() + ownItem->childCount(); ui->label_count->setText( "(" + QString::number( itemCount ) + ")" ); - + int contactsCount = contactsItem->childCount() ; int allCount = allItem->childCount() ; int ownCount = ownItem->childCount(); @@ -1743,7 +1743,7 @@ void IdDialog::loadIdentity(RsGxsIdGroup data) ui->lineEdit_GpgId->show() ; ui->label_GpgId->show() ; } - + if(data.mPgpKnown) { ui->lineEdit_GpgName->show() ; @@ -1783,7 +1783,6 @@ void IdDialog::loadIdentity(RsGxsIdGroup data) if (isOwnId) { - mStateHelper->setWidgetEnabled(ui->ownOpinion_CB, false); mStateHelper->setWidgetEnabled(ui->autoBanIdentities_CB, false); // ui->editIdentity->setEnabled(true); // ui->removeIdentity->setEnabled(true); @@ -1793,8 +1792,6 @@ void IdDialog::loadIdentity(RsGxsIdGroup data) } else { - // No Reputation yet! - mStateHelper->setWidgetEnabled(ui->ownOpinion_CB, true); mStateHelper->setWidgetEnabled(ui->autoBanIdentities_CB, true); // ui->editIdentity->setEnabled(false); // ui->removeIdentity->setEnabled(false); @@ -1838,7 +1835,7 @@ void IdDialog::loadIdentity(RsGxsIdGroup data) frep_string = tr("No votes from friends") ; ui->neighborNodesOpinion_TF->setText(frep_string) ; - + ui->label_positive->setText(QString::number(info.mFriendsPositiveVotes)); ui->label_negative->setText(QString::number(info.mFriendsNegativeVotes)); @@ -2040,7 +2037,7 @@ void IdDialog::modifyReputation() return; } - + void IdDialog::navigate(const RsGxsId& gxs_id) { #ifdef ID_DEBUG @@ -2266,29 +2263,29 @@ void IdDialog::IdListCustomPopupMenu( QPoint ) if(n_is_a_contact == 0) contextMenu->addAction(QIcon(), tr("Add to Contacts"), this, SLOT(addtoContacts())); - if (n_selected_items==1) - contextMenu->addAction(QIcon(""),tr("Copy identity to clipboard"),this,SLOT(copyRetroshareLink())) ; - if(n_is_not_a_contact == 0) contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/cancel.svg"), tr("Remove from Contacts"), this, SLOT(removefromContacts())); - contextMenu->addSeparator(); + } - if(n_positive_reputations == 0) // only unban when all items are banned - contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/thumbs-up.png"), tr("Set positive opinion"), this, SLOT(positivePerson())); + if (n_selected_items==1) + contextMenu->addAction(QIcon(""),tr("Copy identity to clipboard"),this,SLOT(copyRetroshareLink())) ; - if(n_neutral_reputations == 0) // only unban when all items are banned - contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/thumbs-neutral.png"), tr("Set neutral opinion"), this, SLOT(neutralPerson())); + contextMenu->addSeparator(); - if(n_negative_reputations == 0) - contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/thumbs-down.png"), tr("Set negative opinion"), this, SLOT(negativePerson())); - } + if(n_positive_reputations == 0) // only unban when all items are banned + contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/thumbs-up.png"), tr("Set positive opinion"), this, SLOT(positivePerson())); + + if(n_neutral_reputations == 0) // only unban when all items are banned + contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/thumbs-neutral.png"), tr("Set neutral opinion"), this, SLOT(neutralPerson())); + + if(n_negative_reputations == 0) + contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/png/thumbs-down.png"), tr("Set negative opinion"), this, SLOT(negativePerson())); if(one_item_owned_by_you && n_selected_items==1) { contextMenu->addSeparator(); - contextMenu->addAction(QIcon(""),tr("Copy identity to clipboard"),this,SLOT(copyRetroshareLink())) ; contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_EDIT),tr("Edit identity"),this,SLOT(editIdentity())) ; contextMenu->addAction(FilesDefs::getIconFromQtResourcePath(":/icons/cancel.svg"),tr("Delete identity"),this,SLOT(removeIdentity())) ; } @@ -2463,7 +2460,7 @@ void IdDialog::sendInvite() } RsGxsId id(ui->lineEdit_KeyId->text().toStdString()); - + //if ((QMessageBox::question(this, tr("Send invite?"),tr("Do you really want send a invite with your Certificate?"),QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes))== QMessageBox::Yes) { MessageComposer::sendInvite(id,false); @@ -2471,7 +2468,7 @@ void IdDialog::sendInvite() ui->info_Frame_Invite->show(); ui->inviteButton->setEnabled(false); } - + } @@ -2602,4 +2599,3 @@ void IdDialog::restoreExpandedCircleItems(const std::vector& expanded_root restoreTopLevel(mExternalOtherCircleItem,1); restoreTopLevel(mMyCircleItem,2); } - From 2c53c0231930311139605285262d6007957d9bd2 Mon Sep 17 00:00:00 2001 From: David Bears Date: Sat, 4 Jan 2025 13:48:00 -0500 Subject: [PATCH 4/4] omit newline after single link --- retroshare-gui/src/gui/RetroShareLink.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/RetroShareLink.cpp b/retroshare-gui/src/gui/RetroShareLink.cpp index fd3571e7e..0001cd9bc 100644 --- a/retroshare-gui/src/gui/RetroShareLink.cpp +++ b/retroshare-gui/src/gui/RetroShareLink.cpp @@ -1920,7 +1920,9 @@ static void processList(const QStringList &list, const QString &textSingular, co void RSLinkClipboard::copyLinks(const QList& links) { QString res ; - for (int i = 0; i < links.size(); ++i) + if(links.size() == 1) + res += links[0].toString(); + else for(int i = 0; i < links.size(); ++i) res += links[i].toString() + "\n" ; QApplication::clipboard()->setText(res) ; @@ -2036,4 +2038,3 @@ void RSLinkClipboard::parseText(QString text, QList &links,Retro pos += rx.matchedLength(); } } -