RetroShare/retroshare-gui/src/gui/NetworkDialog.cpp
2020-03-05 21:11:16 +01:00

281 lines
11 KiB
C++

/*******************************************************************************
* gui/NetworkDialog.cpp *
* *
* Copyright (c) 2006 Crypton <retroshare.project@gmail.com> *
* *
* 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include <QTreeWidget>
#include <QDebug>
#include <QTimer>
#include <QTime>
#include <QMenu>
#include <QSortFilterProxyModel>
#include <retroshare/rsiface.h>
#include <retroshare/rspeers.h>
#include <retroshare/rsdisc.h>
#include <retroshare/rsmsgs.h>
#include "common/vmessagebox.h"
#include "common/RSTreeWidgetItem.h"
#include <gui/common/FriendSelectionDialog.h>
#include "gui/msgs/MessageComposer.h"
#include "gui/profile/ProfileManager.h"
#include "NetworkDialog.h"
//#include "TrustView.h"
#include "NetworkView.h"
#include "GenCertDialog.h"
#include "connect/PGPKeyDialog.h"
#include "settings/rsharesettings.h"
#include "RetroShareLink.h"
#include "util/QtVersion.h"
#include <time.h>
/* Images for context menu icons */
#define IMAGE_PEERDETAILS ":/images/info16.png"
#define IMAGE_MAKEFRIEND ":/images/user/add_user16.png"
#define IMAGE_COPYLINK ":/images/copyrslink.png"
#define IMAGE_MESSAGE ":/icons/mail/write-mail.png"
/******
* #define NET_DEBUG 1
*****/
/** Constructor */
NetworkDialog::NetworkDialog(QWidget */*parent*/)
{
/* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this);
connect( ui.filterLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterItems(QString)));
connect( ui.filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterColumnChanged(int)));
//list data model
float f = QFontMetricsF(font()).height()/14.0 ;
PGPIdItemModel = new pgpid_item_model(neighs, f, this);
PGPIdItemProxy = new pgpid_item_proxy(this);
connect(ui.onlyTrustedKeys, SIGNAL(toggled(bool)), PGPIdItemProxy, SLOT(use_only_trusted_keys(bool)));
PGPIdItemProxy->setSourceModel(PGPIdItemModel);
PGPIdItemProxy->setFilterKeyColumn(COLUMN_PEERNAME);
PGPIdItemProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
PGPIdItemProxy->setSortRole(Qt::EditRole); //use edit role to get raw data since we do not have edit for this model.
ui.connectTreeWidget->setModel(PGPIdItemProxy);
ui.connectTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui.connectTreeWidget->verticalHeader()->hide();
ui.connectTreeWidget->setShowGrid(false);
ui.connectTreeWidget->setUpdatesEnabled(true);
ui.connectTreeWidget->setSortingEnabled(true);
ui.connectTreeWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui.connectTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
connect(ui.connectTreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( connectTreeWidgetCostumPopupMenu( QPoint ) ) );
connect(ui.connectTreeWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(peerdetails()));
ui.onlyTrustedKeys->setMinimumWidth(20*f);
/* add filter actions */
ui.filterLineEdit->addFilter(QIcon(), tr("Name"), COLUMN_PEERNAME, tr("Search name"));
ui.filterLineEdit->addFilter(QIcon(), tr("Peer ID"), COLUMN_PEERID, tr("Search peer ID"));
ui.filterLineEdit->setCurrentFilter(COLUMN_PEERNAME);
connect(ui.filterLineEdit, SIGNAL(textChanged(QString)), PGPIdItemProxy, SLOT(setFilterWildcard(QString)));
}
void NetworkDialog::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::StyleChange:
securedUpdateDisplay();
break;
default:
// remove compiler warnings
break;
}
}
void NetworkDialog::connectTreeWidgetCostumPopupMenu( QPoint /*point*/ )
{
QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes();
if(l.empty())
{
return;
}
QMenu *contextMnu = new QMenu;
RsPgpId peer_id(ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l.begin()->row(), COLUMN_PEERID)).toString().toStdString()) ;
// That's what context menus are made for
RsPeerDetails detail;
if(!rsPeers->getGPGDetails(peer_id, detail)) // that is not suppose to fail.
return ;
if(peer_id == rsPeers->getGPGOwnId())
contextMnu->addAction(QIcon(), tr("Export/create a new node"), this, SLOT(on_actionExportKey_activated()));
contextMnu->addAction(QIcon(IMAGE_PEERDETAILS), tr("Profile details..."), this, SLOT(peerdetails()));
contextMnu->addSeparator() ;
contextMnu->addAction(QIcon(), tr("Remove unused keys..."), this, SLOT(removeUnusedKeys()));
contextMnu->exec(QCursor::pos());
}
void NetworkDialog::removeUnusedKeys()
{
std::set<RsPgpId> pre_selected ;
std::list<RsPgpId> ids ;
rsPeers->getGPGAllList(ids) ;
RsPeerDetails details ;
time_t now = time(NULL) ;
time_t THREE_MONTHS = 3*31*24*60*60 ;//3*DayPerMonth*HoursPerDay*MinPerHour*SecPerMin
for(std::list<RsPgpId>::const_iterator it(ids.begin());it!=ids.end();++it)
{
rsPeers->getGPGDetails(*it,details) ;
if(rsPeers->haveSecretKey(*it))
{
std::cerr << "Skipping public/secret key pair " << *it << std::endl;
continue ;
}
if(now > (time_t) (THREE_MONTHS + details.lastUsed) && !details.accept_connection)
{
std::cerr << "Adding " << *it << " to pre-selection." << std::endl;
pre_selected.insert(*it) ;
}
}
std::set<RsPgpId> selected = FriendSelectionDialog::selectFriends_PGP(NULL,
tr("Clean keyring"),
tr("The selected keys below haven't been used in the last 3 months. \nDo you want to delete them permanently ? \n\nNotes: Your old keyring will be backed up.\n The removal may fail when running multiple Retroshare instances on the same machine."),FriendSelectionWidget::MODUS_CHECK,FriendSelectionWidget::SHOW_GPG | FriendSelectionWidget::SHOW_NON_FRIEND_GPG,
pre_selected) ;
std::cerr << "Removing these keys from the keyring: " << std::endl;
for(std::set<RsPgpId>::const_iterator it(selected.begin());it!=selected.end();++it)
std::cerr << " " << *it << std::endl;
std::string backup_file ;
uint32_t error_code ;
if(selected.empty())
return ;
if( rsPeers->removeKeysFromPGPKeyring(selected,backup_file,error_code) )
QMessageBox::information(NULL,tr("Keyring info"),tr("%1 keys have been deleted from your keyring. \nFor security, your keyring was previously backed-up to file \n\n").arg(selected.size())+QString::fromStdString(backup_file) ) ;
else
{
QString error_string ;
switch(error_code)
{
default:
case PGP_KEYRING_REMOVAL_ERROR_NO_ERROR: error_string = tr("Unknown error") ;
break ;
case PGP_KEYRING_REMOVAL_ERROR_CANT_REMOVE_SECRET_KEYS: error_string = tr("Cannot delete secret keys") ;
break ;
case PGP_KEYRING_REMOVAL_ERROR_CANNOT_WRITE_BACKUP:
case PGP_KEYRING_REMOVAL_ERROR_CANNOT_CREATE_BACKUP: error_string = tr("Cannot create backup file. Check for permissions in pgp directory, disk space, etc.") ;
break ;
case PGP_KEYRING_REMOVAL_ERROR_DATA_INCONSISTENCY: error_string = tr("Data inconsistency in the keyring. This is most probably a bug. Please contact the developers.") ;
break ;
}
QMessageBox::warning(NULL,tr("Keyring info"),tr("Key removal has failed. Your keyring remains intact.\n\nReported error:")+" "+error_string ) ;
}
updateDisplay();
// insertConnect() ;
}
void NetworkDialog::denyFriend()
{
QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes();
if(l.empty())
return;
RsPgpId peer_id(ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l.begin()->row(), COLUMN_PEERID)).toString().toStdString());
rsPeers->removeFriend(peer_id) ;
securedUpdateDisplay();
}
void NetworkDialog::makeFriend()
{
QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes();
if(l.empty())
return;
PGPKeyDialog::showIt(RsPgpId(ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l.begin()->row(), COLUMN_PEERID)).toString().toStdString()), PGPKeyDialog::PageDetails);
}
/** Shows Peer Information/Auth Dialog */
void NetworkDialog::peerdetails()
{
QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes();
if(l.empty())
return;
PGPKeyDialog::showIt(RsPgpId(ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l.begin()->row(), COLUMN_PEERID)).toString().toStdString()), PGPKeyDialog::PageDetails);
}
void NetworkDialog::copyLink()
{
QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes();
if(l.empty())
return;
RsPgpId peer_id (ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l.begin()->row(), COLUMN_PEERID)).toString().toStdString()) ;
QList<RetroShareLink> urls;
RetroShareLink link = RetroShareLink::createPerson(peer_id);
if (link.valid()) {
urls.push_back(link);
}
RSLinkClipboard::copyLinks(urls);
}
// void NetworkDialog::on_actionExportKey_activated()
// {
// ProfileManager prof ;
// prof.exec() ;
// }
void NetworkDialog::filterColumnChanged(int col)
{
if(PGPIdItemProxy)
PGPIdItemProxy->setFilterKeyColumn(col);
//filterItems(ui.filterLineEdit->text());
}
void NetworkDialog::updateDisplay()
{
if (!rsPeers)
return;
//update ids list
std::list<RsPgpId> new_neighs;
rsPeers->getGPGAllList(new_neighs);
//refresh model
PGPIdItemModel->data_updated(new_neighs);
}