mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2024-11-16 00:12:43 +00:00
884 lines
39 KiB
C++
884 lines
39 KiB
C++
#ifndef MAINWINDOW_H
|
|
#define MAINWINDOW_H
|
|
|
|
#include <QObject>
|
|
#include <QMainWindow>
|
|
#include <QPushButton>
|
|
#include <QtCore/QVariant>
|
|
#include <QtWidgets/QAction>
|
|
#include <QtWidgets/QApplication>
|
|
#include <QtWidgets/QButtonGroup>
|
|
#include <QtWidgets/QHeaderView>
|
|
#include <QtWidgets/QMainWindow>
|
|
#include <QtWidgets/QVBoxLayout>
|
|
#include <QtWidgets/QWidget>
|
|
#include <QtWidgets/QCheckBox>
|
|
#include <QtWidgets/QComboBox>
|
|
#include <QtWidgets/QAction>
|
|
#include <QtWidgets/QGridLayout>
|
|
#include <QtWidgets/QGroupBox>
|
|
#include <QtWidgets/QHBoxLayout>
|
|
#include <QtWidgets/QHeaderView>
|
|
#include <QtWidgets/QLabel>
|
|
#include <QtWidgets/QLineEdit>
|
|
#include <QtWidgets/QPushButton>
|
|
#include <QtWidgets/QSpacerItem>
|
|
#include "QVBoxLayout"
|
|
#include "QUrl"
|
|
|
|
#ifndef ANDROID
|
|
# include <QSystemTrayIcon>
|
|
# include <QCloseEvent>
|
|
# include <QMenu>
|
|
#endif
|
|
|
|
#include <QString>
|
|
|
|
#include <functional>
|
|
|
|
#include "MainWindowItems.h"
|
|
#include "TunnelPane.h"
|
|
#include "ServerTunnelPane.h"
|
|
#include "ClientTunnelPane.h"
|
|
#include "TunnelConfig.h"
|
|
#include "textbrowsertweaked1.h"
|
|
|
|
#include "Config.h"
|
|
#include "FS.h"
|
|
|
|
#include <QDebug>
|
|
|
|
#include <boost/property_tree/ptree.hpp>
|
|
#include <boost/property_tree/ini_parser.hpp>
|
|
|
|
#include "TunnelsPageUpdateListener.h"
|
|
|
|
#include "DaemonQT.h"
|
|
#include "SignatureTypeComboboxFactory.h"
|
|
#include "pagewithbackbutton.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include "widgetlockregistry.h"
|
|
#include "widgetlock.h"
|
|
|
|
#include "DelayedSaveManager.h"
|
|
#include "DelayedSaveManagerImpl.h"
|
|
#include "SaverImpl.h"
|
|
|
|
#include "I2pdQtUtil.h"
|
|
|
|
class SaverImpl;
|
|
|
|
class LogViewerManager;
|
|
|
|
template<typename ValueType>
|
|
bool isType(boost::any& a) {
|
|
return
|
|
#ifdef BOOST_AUX_ANY_TYPE_ID_NAME
|
|
std::strcmp(a.type().name(), typeid(ValueType).name()) == 0
|
|
#else
|
|
a.type() == typeid(ValueType)
|
|
#endif
|
|
;
|
|
}
|
|
|
|
class ConfigOption {
|
|
public:
|
|
QString section;
|
|
QString option;
|
|
//MainWindow::DefaultValueGetter defaultValueGetter;
|
|
ConfigOption(QString section_, QString option_/*, DefaultValueGetter defaultValueGetter_*/):
|
|
section(section_)
|
|
, option(option_)
|
|
//, defaultValueGetter(defaultValueGetter_)
|
|
{}
|
|
|
|
};
|
|
|
|
extern std::string programOptionsWriterCurrentSection;
|
|
|
|
class MainWindow;
|
|
|
|
class MainWindowItem : public QObject {
|
|
Q_OBJECT
|
|
private:
|
|
ConfigOption option;
|
|
QWidget* widgetToFocus;
|
|
QString requirementToBeValid;
|
|
const bool readOnly;
|
|
public:
|
|
MainWindowItem(ConfigOption option_, QWidget* widgetToFocus_, QString requirementToBeValid_, bool readOnly_=false) :
|
|
option(option_), widgetToFocus(widgetToFocus_), requirementToBeValid(requirementToBeValid_), readOnly(readOnly_) {}
|
|
QWidget* getWidgetToFocus(){return widgetToFocus;}
|
|
QString& getRequirementToBeValid() { return requirementToBeValid; }
|
|
ConfigOption& getConfigOption() { return option; }
|
|
boost::any optionValue;
|
|
virtual ~MainWindowItem(){}
|
|
virtual void installListeners(MainWindow *mainWindow);
|
|
virtual void loadFromConfigOption(){
|
|
std::string optName="";
|
|
if(!option.section.isEmpty())optName=option.section.toStdString()+std::string(".");
|
|
optName+=option.option.toStdString();
|
|
//qDebug() << "loadFromConfigOption[" << optName.c_str() << "]";
|
|
boost::any programOption;
|
|
i2p::config::GetOptionAsAny(optName, programOption);
|
|
optionValue=programOption.empty()?boost::any(std::string(""))
|
|
:boost::any_cast<boost::program_options::variable_value>(programOption).value();
|
|
}
|
|
virtual void saveToStringStream(std::stringstream& out){
|
|
if(readOnly)return; //should readOnly items (conf=) error somewhere, instead of silently skipping save?
|
|
if(isType<std::string>(optionValue)) {
|
|
std::string v = boost::any_cast<std::string>(optionValue);
|
|
if(v.empty())return;
|
|
}
|
|
if(optionValue.empty())return;
|
|
std::string rtti = optionValue.type().name();
|
|
std::string optName="";
|
|
if(!option.section.isEmpty())optName=option.section.toStdString()+std::string(".");
|
|
optName+=option.option.toStdString();
|
|
//qDebug() << "Writing option" << optName.c_str() << "of type" << rtti.c_str();
|
|
std::string sectionAsStdStr = option.section.toStdString();
|
|
if(!option.section.isEmpty() &&
|
|
sectionAsStdStr!=programOptionsWriterCurrentSection) {
|
|
out << "[" << sectionAsStdStr << "]\n";
|
|
programOptionsWriterCurrentSection=sectionAsStdStr;
|
|
}
|
|
out << option.option.toStdString() << "=";
|
|
if(isType<std::string>(optionValue)) {
|
|
out << boost::any_cast<std::string>(optionValue);
|
|
}else if(isType<bool>(optionValue)) {
|
|
out << (boost::any_cast<bool>(optionValue) ? "true" : "false");
|
|
}else if(isType<uint16_t>(optionValue)) {
|
|
out << boost::any_cast<uint16_t>(optionValue);
|
|
}else if(isType<uint32_t>(optionValue)) {
|
|
out << boost::any_cast<uint32_t>(optionValue);
|
|
}else if(isType<int>(optionValue)) {
|
|
out << boost::any_cast<int>(optionValue);
|
|
}else if(isType<unsigned short>(optionValue)) {
|
|
out << boost::any_cast<unsigned short>(optionValue);
|
|
}else out << boost::any_cast<std::string>(optionValue); //let it throw
|
|
out << "\n\n";
|
|
}
|
|
virtual bool isValid(bool & alreadyDisplayedIfWrong){alreadyDisplayedIfWrong=false;return true;}
|
|
};
|
|
class NonGUIOptionItem : public MainWindowItem {
|
|
public:
|
|
NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_, nullptr, QString()) {}
|
|
virtual ~NonGUIOptionItem(){}
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; }
|
|
};
|
|
class BaseStringItem : public MainWindowItem {
|
|
Q_OBJECT
|
|
public:
|
|
QLineEdit* lineEdit;
|
|
MainWindow *mainWindow;
|
|
BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_, MainWindow* mainWindow_, bool readOnly=false):
|
|
MainWindowItem(option_, lineEdit_, requirementToBeValid_, readOnly),
|
|
lineEdit(lineEdit_),
|
|
mainWindow(mainWindow_)
|
|
{};
|
|
virtual ~BaseStringItem(){}
|
|
virtual void installListeners(MainWindow *mainWindow);
|
|
virtual QString toString(){
|
|
return boost::any_cast<std::string>(optionValue).c_str();
|
|
}
|
|
virtual boost::any fromString(QString s){return boost::any(s.toStdString());}
|
|
virtual void loadFromConfigOption(){
|
|
MainWindowItem::loadFromConfigOption();
|
|
lineEdit->setText(toString());
|
|
}
|
|
|
|
virtual void saveToStringStream(std::stringstream& out){
|
|
optionValue=fromString(lineEdit->text());
|
|
MainWindowItem::saveToStringStream(out);
|
|
}
|
|
virtual bool isValid(bool & alreadyDisplayedIfWrong);
|
|
};
|
|
class FileOrFolderChooserItem : public BaseStringItem {
|
|
protected:
|
|
const bool requireExistingFile;
|
|
public:
|
|
QPushButton* browsePushButton;
|
|
FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile_, bool readOnly) :
|
|
BaseStringItem(option_, lineEdit_, QString(), mw, readOnly), requireExistingFile(requireExistingFile_), browsePushButton(browsePushButton_) {}
|
|
virtual ~FileOrFolderChooserItem(){}
|
|
};
|
|
class FileChooserItem : public FileOrFolderChooserItem {
|
|
Q_OBJECT
|
|
private slots:
|
|
void pushButtonReleased();
|
|
public:
|
|
FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFile, bool readOnly) :
|
|
FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFile, readOnly) {
|
|
QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased()));
|
|
}
|
|
};
|
|
class FolderChooserItem : public FileOrFolderChooserItem{
|
|
Q_OBJECT
|
|
private slots:
|
|
void pushButtonReleased();
|
|
public:
|
|
FolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_, MainWindow* mw, bool requireExistingFolder) :
|
|
FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_, mw, requireExistingFolder, false) {
|
|
QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased()));
|
|
}
|
|
};
|
|
class ComboBoxItem : public MainWindowItem {
|
|
public:
|
|
QComboBox* comboBox;
|
|
ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_,comboBox_,QString()), comboBox(comboBox_){}
|
|
virtual ~ComboBoxItem(){}
|
|
virtual void installListeners(MainWindow *mainWindow);
|
|
virtual void loadFromConfigOption()=0;
|
|
virtual void saveToStringStream(std::stringstream& out)=0;
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong) { return ; }
|
|
};
|
|
class LogDestinationComboBoxItem : public ComboBoxItem {
|
|
public:
|
|
LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) :
|
|
ComboBoxItem(option_, comboBox_) {}
|
|
virtual ~LogDestinationComboBoxItem(){}
|
|
virtual void loadFromConfigOption(){
|
|
MainWindowItem::loadFromConfigOption();
|
|
const char * ld = boost::any_cast<std::string>(optionValue).c_str();
|
|
comboBox->setCurrentText(QString(ld));
|
|
}
|
|
virtual void saveToStringStream(std::stringstream& out){
|
|
std::string logDest = comboBox->currentText().toStdString();
|
|
optionValue=logDest;
|
|
MainWindowItem::saveToStringStream(out);
|
|
}
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; }
|
|
|
|
Q_OBJECT
|
|
};
|
|
class LogLevelComboBoxItem : public ComboBoxItem {
|
|
public:
|
|
LogLevelComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}
|
|
virtual ~LogLevelComboBoxItem(){}
|
|
virtual void loadFromConfigOption(){
|
|
MainWindowItem::loadFromConfigOption();
|
|
const char * ll = boost::any_cast<std::string>(optionValue).c_str();
|
|
comboBox->setCurrentText(QString(ll));
|
|
}
|
|
virtual void saveToStringStream(std::stringstream& out){
|
|
optionValue=comboBox->currentText().toStdString();
|
|
MainWindowItem::saveToStringStream(out);
|
|
}
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; }
|
|
};
|
|
class SignatureTypeComboBoxItem : public ComboBoxItem {
|
|
public:
|
|
SignatureTypeComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}
|
|
virtual ~SignatureTypeComboBoxItem(){}
|
|
virtual void loadFromConfigOption(){
|
|
MainWindowItem::loadFromConfigOption();
|
|
while(comboBox->count()>0)comboBox->removeItem(0);
|
|
uint16_t selected = (uint16_t) boost::any_cast<unsigned short>(optionValue);
|
|
SignatureTypeComboBoxFactory::fillComboBox(comboBox, selected);
|
|
}
|
|
virtual void saveToStringStream(std::stringstream& out){
|
|
uint16_t selected = SignatureTypeComboBoxFactory::getSigType(comboBox->currentData());
|
|
optionValue=(unsigned short)selected;
|
|
MainWindowItem::saveToStringStream(out);
|
|
}
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; }
|
|
};
|
|
class CheckBoxItem : public MainWindowItem {
|
|
public:
|
|
QCheckBox* checkBox;
|
|
CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_,checkBox_,QString()), checkBox(checkBox_){}
|
|
virtual ~CheckBoxItem(){}
|
|
virtual void installListeners(MainWindow *mainWindow);
|
|
virtual void loadFromConfigOption(){
|
|
MainWindowItem::loadFromConfigOption();
|
|
//qDebug() << "setting value for checkbox " << checkBox->text();
|
|
checkBox->setChecked(boost::any_cast<bool>(optionValue));
|
|
}
|
|
virtual void saveToStringStream(std::stringstream& out){
|
|
optionValue=checkBox->isChecked();
|
|
MainWindowItem::saveToStringStream(out);
|
|
}
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong) { return true; }
|
|
};
|
|
class BaseFormattedStringItem : public BaseStringItem {
|
|
public:
|
|
QString fieldNameTranslated;
|
|
BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, QString requirementToBeValid_, MainWindow* mw) :
|
|
BaseStringItem(option_, lineEdit_, requirementToBeValid_, mw), fieldNameTranslated(fieldNameTranslated_) {}
|
|
virtual ~BaseFormattedStringItem(){}
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong)=0;
|
|
};
|
|
class IntegerStringItem : public BaseFormattedStringItem {
|
|
public:
|
|
IntegerStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) :
|
|
BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be a valid integer."), mw) {}
|
|
virtual ~IntegerStringItem(){}
|
|
virtual bool isValid(bool & alreadyDisplayedIfWrong){
|
|
bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong);
|
|
if(!correct)return false;
|
|
alreadyDisplayedIfWrong = false;
|
|
auto str=lineEdit->text();
|
|
bool ok;
|
|
str.toInt(&ok);
|
|
return ok;
|
|
}
|
|
virtual QString toString(){return QString::number(boost::any_cast<int>(optionValue));}
|
|
virtual boost::any fromString(QString s){return boost::any(std::stoi(s.toStdString()));}
|
|
};
|
|
class UShortStringItem : public BaseFormattedStringItem {
|
|
public:
|
|
UShortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) :
|
|
BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned short integer."), mw) {}
|
|
virtual ~UShortStringItem(){}
|
|
virtual bool isValid(bool & alreadyDisplayedIfWrong){
|
|
bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong);
|
|
if(!correct)return false;
|
|
alreadyDisplayedIfWrong = false;
|
|
auto str=lineEdit->text();
|
|
bool ok;
|
|
str.toUShort(&ok);
|
|
return ok;
|
|
}
|
|
virtual QString toString(){return QString::number(boost::any_cast<unsigned short>(optionValue));}
|
|
virtual boost::any fromString(QString s){return boost::any((unsigned short)std::stoi(s.toStdString()));}
|
|
};
|
|
class UInt32StringItem : public BaseFormattedStringItem {
|
|
public:
|
|
UInt32StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) :
|
|
BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 32-bit integer."), mw) {}
|
|
virtual ~UInt32StringItem(){}
|
|
virtual bool isValid(bool & alreadyDisplayedIfWrong){
|
|
bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong);
|
|
if(!correct)return false;
|
|
alreadyDisplayedIfWrong = false;
|
|
auto str=lineEdit->text();
|
|
bool ok;
|
|
str.toUInt(&ok);
|
|
return ok;
|
|
}
|
|
virtual QString toString(){return QString::number(boost::any_cast<uint32_t>(optionValue));}
|
|
virtual boost::any fromString(QString s){return boost::any((uint32_t)std::stoi(s.toStdString()));}
|
|
};
|
|
class UInt16StringItem : public BaseFormattedStringItem {
|
|
public:
|
|
UInt16StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) :
|
|
BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 16-bit integer."), mw) {}
|
|
virtual ~UInt16StringItem(){}
|
|
virtual bool isValid(bool & alreadyDisplayedIfWrong){
|
|
bool correct = BaseFormattedStringItem::isValid(alreadyDisplayedIfWrong);
|
|
if(!correct)return false;
|
|
alreadyDisplayedIfWrong = false;
|
|
auto str=lineEdit->text();
|
|
bool ok;
|
|
str.toUShort(&ok);
|
|
return ok;
|
|
}
|
|
virtual QString toString(){return QString::number(boost::any_cast<uint16_t>(optionValue));}
|
|
virtual boost::any fromString(QString s){return boost::any((uint16_t)std::stoi(s.toStdString()));}
|
|
};
|
|
class IPAddressStringItem : public BaseFormattedStringItem {
|
|
public:
|
|
IPAddressStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) :
|
|
BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be an IPv4 address"), mw) {}
|
|
//virtual bool isValid(bool & alreadyDisplayedIfWrong){return true;}//todo
|
|
};
|
|
class TCPPortStringItem : public UShortStringItem {
|
|
public:
|
|
TCPPortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, MainWindow* mw) :
|
|
UShortStringItem(option_, lineEdit_, fieldNameTranslated_,mw) {}
|
|
};
|
|
|
|
namespace Ui {
|
|
class MainWindow;
|
|
class StatusButtonsForm;
|
|
class routerCommandsWidget;
|
|
class GeneralSettingsContentsForm;
|
|
}
|
|
|
|
using namespace i2p::client;
|
|
|
|
class TunnelPane;
|
|
|
|
using namespace i2p::qt;
|
|
|
|
class Controller;
|
|
|
|
class DelayedSaveManagerImpl;
|
|
|
|
class MainWindow : public QMainWindow {
|
|
Q_OBJECT
|
|
private:
|
|
std::string currentLocalDestinationB32;
|
|
std::shared_ptr<std::iostream> logStream;
|
|
DelayedSaveManagerImpl* delayedSaveManagerPtr;
|
|
DelayedSaveManager::DATA_SERIAL_TYPE dataSerial;
|
|
public:
|
|
explicit MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *parent=nullptr);
|
|
~MainWindow();
|
|
|
|
void setI2PController(i2p::qt::Controller* controller_);
|
|
|
|
void highlightWrongInput(QString warningText, WrongInputPageEnum inputPage, QWidget* widgetToFocus);
|
|
|
|
//typedef std::function<QString ()> DefaultValueGetter;
|
|
|
|
//#ifndef ANDROID
|
|
// void setVisible(bool visible);
|
|
//#endif
|
|
|
|
private:
|
|
enum StatusPage {main_page, commands, local_destinations, leasesets, tunnels, transit_tunnels,
|
|
transports, i2p_tunnels, sam_sessions};
|
|
private slots:
|
|
void updated();
|
|
|
|
void handleQuitButton();
|
|
void handleGracefulQuitButton();
|
|
void handleDoRestartButton();
|
|
void handleGracefulQuitTimerEvent();
|
|
#ifndef ANDROID
|
|
void setIcon();
|
|
void iconActivated(QSystemTrayIcon::ActivationReason reason);
|
|
void toggleVisibilitySlot();
|
|
#endif
|
|
void scheduleStatusPageUpdates();
|
|
void statusHtmlPageMouseReleased();
|
|
void statusHtmlPageSelectionChanged();
|
|
void updateStatusPage();
|
|
|
|
void showStatusMainPage();
|
|
void showStatus_commands_Page();
|
|
void runPeerTest();
|
|
void enableTransit();
|
|
void disableTransit();
|
|
|
|
public slots:
|
|
void syncLogLevel (int comboBoxIndex);
|
|
|
|
void showStatus_local_destinations_Page();
|
|
void showStatus_leasesets_Page();
|
|
void showStatus_tunnels_Page();
|
|
void showStatus_transit_tunnels_Page();
|
|
void showStatus_transports_Page();
|
|
void showStatus_i2p_tunnels_Page();
|
|
void showStatus_sam_sessions_Page();
|
|
|
|
void showLogViewerPage();
|
|
void showSettingsPage();
|
|
void showTunnelsPage();
|
|
void showRestartPage();
|
|
void showQuitPage();
|
|
void showAboutBox(const QString & href);
|
|
|
|
private:
|
|
StatusPage statusPage;
|
|
QTimer * statusPageUpdateTimer;
|
|
bool wasSelectingAtStatusMainPage;
|
|
bool showHiddenInfoStatusMainPage;
|
|
|
|
LogViewerManager *logViewerManagerPtr;
|
|
|
|
void showStatusPage(StatusPage newStatusPage);
|
|
#ifndef ANDROID
|
|
void createActions();
|
|
void createTrayIcon();
|
|
bool quitting;
|
|
QAction *toggleWindowVisibleAction;
|
|
QSystemTrayIcon *trayIcon;
|
|
QMenu *trayIconMenu;
|
|
#endif
|
|
|
|
public:
|
|
Ui::MainWindow* ui;
|
|
Ui::StatusButtonsForm* statusButtonsUI;
|
|
Ui::routerCommandsWidget* routerCommandsUI;
|
|
Ui::GeneralSettingsContentsForm* uiSettings;
|
|
void adjustSizesAccordingToWrongLabel();
|
|
bool applyTunnelsUiToConfigs();
|
|
private:
|
|
int settingsTitleLabelNominalHeight;
|
|
TextBrowserTweaked1 * textBrowser;
|
|
QWidget * routerCommandsParent;
|
|
PageWithBackButton * pageWithBackButton;
|
|
TextBrowserTweaked1 * childTextBrowser;
|
|
|
|
widgetlockregistry widgetlocks;
|
|
|
|
i2p::qt::Controller* i2pController;
|
|
|
|
protected:
|
|
|
|
void updateRouterCommandsButtons();
|
|
|
|
#ifndef ANDROID
|
|
void closeEvent(QCloseEvent *event);
|
|
#endif
|
|
void resizeEvent(QResizeEvent* event);
|
|
void onResize();
|
|
|
|
void setStatusButtonsVisible(bool visible);
|
|
|
|
QString getStatusPageHtml(bool showHiddenInfo);
|
|
|
|
QList<MainWindowItem*> configItems;
|
|
NonGUIOptionItem* daemonOption;
|
|
NonGUIOptionItem* serviceOption;
|
|
//LogDestinationComboBoxItem* logOption;
|
|
FileChooserItem* logFileNameOption;
|
|
|
|
FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton, bool requireExistingFile, bool readOnly=false);
|
|
void initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton);
|
|
//void initCombobox(ConfigOption option, QComboBox* comboBox);
|
|
void initLogDestinationCombobox(ConfigOption option, QComboBox* comboBox);
|
|
void initLogLevelCombobox(ConfigOption option, QComboBox* comboBox);
|
|
void initSignatureTypeCombobox(ConfigOption option, QComboBox* comboBox);
|
|
void initIPAddressBox(ConfigOption option, QLineEdit* addressLineEdit, QString fieldNameTranslated);
|
|
void initTCPPortBox(ConfigOption option, QLineEdit* portLineEdit, QString fieldNameTranslated);
|
|
void initCheckBox(ConfigOption option, QCheckBox* checkBox);
|
|
void initIntegerBox(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated);
|
|
void initUInt32Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated);
|
|
void initUInt16Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated);
|
|
void initStringBox(ConfigOption option, QLineEdit* lineEdit);
|
|
NonGUIOptionItem* initNonGUIOption(ConfigOption option);
|
|
|
|
void loadAllConfigs(SaverImpl* saverPtr);
|
|
void layoutTunnels();
|
|
|
|
public slots:
|
|
/** returns false iff not valid items present and save was aborted */
|
|
bool saveAllConfigs(bool reloadAfterSave, FocusEnum focusOn, std::string tunnelNameToFocus="", QWidget* widgetToFocus=nullptr);
|
|
void reloadTunnelsConfigAndUI(std::string tunnelNameToFocus, QWidget* widgetToFocus);
|
|
void reloadTunnelsConfigAndUI() { reloadTunnelsConfigAndUI("", nullptr); }
|
|
|
|
//focus none
|
|
void reloadTunnelsConfigAndUI_QString(QString tunnelNameToFocus);
|
|
void addServerTunnelPushButtonReleased();
|
|
void addClientTunnelPushButtonReleased();
|
|
|
|
void anchorClickedHandler(const QUrl & link);
|
|
void backClickedFromChild();
|
|
|
|
void logDestinationComboBoxValueChanged(const QString & text);
|
|
|
|
private:
|
|
QString datadir;
|
|
QString confpath;
|
|
QString tunconfpath;
|
|
|
|
std::map<std::string, TunnelConfig*> tunnelConfigs;
|
|
std::list<TunnelPane*> tunnelPanes;
|
|
|
|
void appendTunnelForms(std::string tunnelNameToFocus);
|
|
void deleteTunnelForms();
|
|
void deleteTunnelFromUI(std::string tunnelName, TunnelConfig* cnf);
|
|
|
|
template<typename Section>
|
|
std::string GetI2CPOption (const Section& section, const std::string& name, const std::string& value) const
|
|
{
|
|
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value);
|
|
}
|
|
|
|
template<typename Section>
|
|
std::string GetI2CPOption (const Section& section, const std::string& name, const char* value) const
|
|
{
|
|
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::string (value));
|
|
}
|
|
|
|
template<typename Section, typename Type>
|
|
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
|
{
|
|
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
|
|
}
|
|
|
|
template<typename Section>
|
|
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options, I2CPParameters& param
|
|
/*TODO fill param*/) const
|
|
{
|
|
std::string _INBOUND_TUNNEL_LENGTH = options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNEL_LENGTH, DEFAULT_INBOUND_TUNNEL_LENGTH);
|
|
param.setInbound_length(QString(_INBOUND_TUNNEL_LENGTH.c_str()));
|
|
std::string _OUTBOUND_TUNNEL_LENGTH = options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH);
|
|
param.setOutbound_length(QString(_OUTBOUND_TUNNEL_LENGTH.c_str()));
|
|
std::string _INBOUND_TUNNELS_QUANTITY = options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY);
|
|
param.setInbound_quantity( QString(_INBOUND_TUNNELS_QUANTITY.c_str()));
|
|
std::string _OUTBOUND_TUNNELS_QUANTITY = options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY);
|
|
param.setOutbound_quantity(QString(_OUTBOUND_TUNNELS_QUANTITY.c_str()));
|
|
std::string _TAGS_TO_SEND = options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
|
|
param.setCrypto_tagsToSend(QString(_TAGS_TO_SEND.c_str()));
|
|
std::string _i2cp_leaseSetAuthType = options[I2CP_PARAM_LEASESET_AUTH_TYPE] = GetI2CPOption (section, I2CP_PARAM_LEASESET_AUTH_TYPE, 0);
|
|
param.set_i2cp_leaseSetAuthType(QString(_i2cp_leaseSetAuthType.c_str()));
|
|
const char DEFAULT_LEASESET_ENCRYPTION_TYPE[] = "";
|
|
std::string _i2cp_leaseSetEncType = options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = GetI2CPOption (section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, DEFAULT_LEASESET_ENCRYPTION_TYPE);//todo Identity's type by default
|
|
param.set_i2cp_leaseSetEncType(QString(_i2cp_leaseSetEncType.c_str()));
|
|
std::string _i2cp_leaseSetPrivKey = options[I2CP_PARAM_LEASESET_PRIV_KEY] = GetI2CPOption (section, I2CP_PARAM_LEASESET_PRIV_KEY, "");
|
|
param.set_i2cp_leaseSetPrivKey(QString(_i2cp_leaseSetPrivKey.c_str()));
|
|
std::string _i2cp_leaseSetType = options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption (section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
|
|
param.set_i2cp_leaseSetType(QString(_i2cp_leaseSetType.c_str()));
|
|
std::string _i2p_streaming_answerPings= options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption (section, I2CP_PARAM_STREAMING_ANSWER_PINGS, DEFAULT_ANSWER_PINGS);
|
|
param.set_i2p_streaming_answerPings((_i2p_streaming_answerPings.compare("true")==0)||(_i2p_streaming_answerPings.compare("yes")==0));
|
|
std::string _i2p_streaming_initialAckDelay = options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption (section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
|
|
param.set_i2p_streaming_initialAckDelay(QString(_i2p_streaming_initialAckDelay.c_str()));
|
|
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);//TODO include into param
|
|
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);//TODO include into param
|
|
}
|
|
|
|
void CreateDefaultI2CPOptions (I2CPParameters& param
|
|
/*TODO fill param*/) const
|
|
{
|
|
const int _INBOUND_TUNNEL_LENGTH = DEFAULT_INBOUND_TUNNEL_LENGTH;
|
|
param.setInbound_length(QString::number(_INBOUND_TUNNEL_LENGTH));
|
|
const int _OUTBOUND_TUNNEL_LENGTH = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
|
|
param.setOutbound_length(QString::number(_OUTBOUND_TUNNEL_LENGTH));
|
|
const int _INBOUND_TUNNELS_QUANTITY = DEFAULT_INBOUND_TUNNELS_QUANTITY;
|
|
param.setInbound_quantity( QString::number(_INBOUND_TUNNELS_QUANTITY));
|
|
const int _OUTBOUND_TUNNELS_QUANTITY = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
|
|
param.setOutbound_quantity(QString::number(_OUTBOUND_TUNNELS_QUANTITY));
|
|
const int _TAGS_TO_SEND = DEFAULT_TAGS_TO_SEND;
|
|
param.setCrypto_tagsToSend(QString::number(_TAGS_TO_SEND));
|
|
const int _i2cp_leaseSetAuthType = 0;
|
|
param.set_i2cp_leaseSetAuthType(QString::number(_i2cp_leaseSetAuthType));
|
|
const QString _i2cp_leaseSetEncType = "0,4"; //todo Identity's type by default
|
|
param.set_i2cp_leaseSetEncType(_i2cp_leaseSetEncType);
|
|
param.set_i2cp_leaseSetPrivKey("");
|
|
const int _i2cp_leaseSetType = DEFAULT_LEASESET_TYPE;
|
|
param.set_i2cp_leaseSetType(QString::number(_i2cp_leaseSetType));
|
|
bool _i2p_streaming_answerPings= DEFAULT_ANSWER_PINGS;
|
|
param.set_i2p_streaming_answerPings(_i2p_streaming_answerPings);
|
|
const int _i2p_streaming_initialAckDelay = DEFAULT_INITIAL_ACK_DELAY;
|
|
param.set_i2p_streaming_initialAckDelay(QString::number(_i2p_streaming_initialAckDelay));
|
|
}
|
|
|
|
|
|
void DeleteTunnelNamed(std::string name) {
|
|
std::map<std::string,TunnelConfig*>::const_iterator it=tunnelConfigs.find(name);
|
|
if(it!=tunnelConfigs.end()){
|
|
TunnelConfig* tc=it->second;
|
|
deleteTunnelFromUI(name, tc);
|
|
tunnelConfigs.erase(it);
|
|
delete tc;
|
|
}
|
|
saveAllConfigs(true, FocusEnum::noFocus);
|
|
}
|
|
|
|
std::string GenerateNewTunnelName() {
|
|
int i=1;
|
|
while(true){
|
|
std::stringstream name;
|
|
name << "name" << i;
|
|
const std::string& str=name.str();
|
|
if(tunnelConfigs.find(str)==tunnelConfigs.end())return str;
|
|
++i;
|
|
}
|
|
}
|
|
|
|
void CreateDefaultClientTunnel() {//TODO dedup default values with ReadTunnelsConfig() and with ClientContext.cpp::ReadTunnels ()
|
|
std::string name=GenerateNewTunnelName();
|
|
std::string type = I2P_TUNNELS_SECTION_TYPE_CLIENT;
|
|
std::string dest = "127.0.0.1";
|
|
int port = 0;
|
|
std::string keys = "";
|
|
std::string address = "127.0.0.1";
|
|
int destinationPort = 0;
|
|
int cryptoType = 0;
|
|
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256;
|
|
// I2CP
|
|
I2CPParameters i2cpParameters;
|
|
CreateDefaultI2CPOptions (i2cpParameters);
|
|
|
|
tunnelConfigs[name]=new ClientTunnelConfig(name, QString(type.c_str()), i2cpParameters,
|
|
dest,
|
|
port,
|
|
keys,
|
|
address,
|
|
destinationPort,
|
|
sigType,
|
|
cryptoType);
|
|
|
|
saveAllConfigs(true, FocusEnum::focusOnTunnelName, name);
|
|
}
|
|
|
|
void CreateDefaultServerTunnel() {//TODO dedup default values with ReadTunnelsConfig() and with ClientContext.cpp::ReadTunnels ()
|
|
std::string name=GenerateNewTunnelName();
|
|
std::string type=I2P_TUNNELS_SECTION_TYPE_SERVER;
|
|
std::string host = "127.0.0.1";
|
|
int port = 0;
|
|
std::string keys = "";
|
|
int inPort = 0;
|
|
std::string accessList = "";
|
|
std::string hostOverride = "";
|
|
std::string webircpass = "";
|
|
bool gzip = true;
|
|
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256;
|
|
std::string address = "127.0.0.1";
|
|
bool isUniqueLocal = true;
|
|
int cryptoType = 0;
|
|
|
|
// I2CP
|
|
I2CPParameters i2cpParameters;
|
|
CreateDefaultI2CPOptions (i2cpParameters);
|
|
|
|
tunnelConfigs[name]=new ServerTunnelConfig(name, QString(type.c_str()), i2cpParameters,
|
|
host,
|
|
port,
|
|
keys,
|
|
inPort,
|
|
accessList,
|
|
hostOverride,
|
|
webircpass,
|
|
gzip,
|
|
sigType,
|
|
address,
|
|
isUniqueLocal,
|
|
cryptoType);
|
|
|
|
|
|
saveAllConfigs(true, FocusEnum::focusOnTunnelName, name);
|
|
}
|
|
|
|
void ReadTunnelsConfig() //TODO deduplicate the code with ClientContext.cpp::ReadTunnels ()
|
|
{
|
|
boost::property_tree::ptree pt;
|
|
std::string tunConf=tunconfpath.toStdString();
|
|
if (tunConf == "") {
|
|
// TODO: cleanup this in 2.8.0
|
|
tunConf = i2p::fs::DataDirPath ("tunnels.cfg");
|
|
if (i2p::fs::Exists(tunConf)) {
|
|
LogPrint(eLogWarning, "FS: please rename tunnels.cfg -> tunnels.conf here: ", tunConf);
|
|
} else {
|
|
tunConf = i2p::fs::DataDirPath ("tunnels.conf");
|
|
}
|
|
}
|
|
LogPrint(eLogDebug, "tunnels config file: ", tunConf);
|
|
try
|
|
{
|
|
boost::property_tree::read_ini (tunConf, pt);
|
|
}
|
|
catch (std::exception& ex)
|
|
{
|
|
LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());//TODO show err box and disable tunn.page
|
|
return;
|
|
}
|
|
|
|
for (auto& section: pt)
|
|
{
|
|
std::string name = section.first;
|
|
try
|
|
{
|
|
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE);
|
|
if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT
|
|
|| type == I2P_TUNNELS_SECTION_TYPE_SOCKS
|
|
|| type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS
|
|
|| type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY
|
|
|| type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT)
|
|
{
|
|
// mandatory params
|
|
std::string dest;
|
|
if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) {
|
|
dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
|
|
}
|
|
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
|
|
// optional params
|
|
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
|
|
std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
|
|
int cryptoType = section.second.get<int>(I2P_CLIENT_TUNNEL_CRYPTO_TYPE, 0);
|
|
int destinationPort = section.second.get<int>(I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
|
|
i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
|
// I2CP
|
|
std::map<std::string, std::string> options;
|
|
I2CPParameters i2cpParameters;
|
|
ReadI2CPOptions (section, options, i2cpParameters);
|
|
|
|
tunnelConfigs[name]=new ClientTunnelConfig(name, QString(type.c_str()), i2cpParameters,
|
|
dest,
|
|
port,
|
|
keys,
|
|
address,
|
|
destinationPort,
|
|
sigType,
|
|
cryptoType);
|
|
}
|
|
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER
|
|
|| type == I2P_TUNNELS_SECTION_TYPE_HTTP
|
|
|| type == I2P_TUNNELS_SECTION_TYPE_IRC
|
|
|| type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
|
|
{
|
|
// mandatory params
|
|
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
|
|
int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT);
|
|
// optional params
|
|
std::string keys = section.second.get<std::string> (I2P_SERVER_TUNNEL_KEYS, "");
|
|
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
|
|
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
|
|
std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, "");
|
|
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
|
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
|
|
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
|
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
|
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
|
int cryptoType = section.second.get<int>(I2P_CLIENT_TUNNEL_CRYPTO_TYPE, 0);
|
|
|
|
// I2CP
|
|
std::map<std::string, std::string> options;
|
|
I2CPParameters i2cpParameters;
|
|
ReadI2CPOptions (section, options, i2cpParameters);
|
|
|
|
/*
|
|
std::set<i2p::data::IdentHash> idents;
|
|
if (accessList.length () > 0)
|
|
{
|
|
size_t pos = 0, comma;
|
|
do
|
|
{
|
|
comma = accessList.find (',', pos);
|
|
i2p::data::IdentHash ident;
|
|
ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
|
|
idents.insert (ident);
|
|
pos = comma + 1;
|
|
}
|
|
while (comma != std::string::npos);
|
|
}
|
|
*/
|
|
tunnelConfigs[name]=new ServerTunnelConfig(name, QString(type.c_str()), i2cpParameters,
|
|
host,
|
|
port,
|
|
keys,
|
|
inPort,
|
|
accessList,
|
|
hostOverride,
|
|
webircpass,
|
|
gzip,
|
|
sigType,
|
|
address,
|
|
isUniqueLocal,
|
|
cryptoType);
|
|
}
|
|
else
|
|
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);//TODO show err box and disable the tunn gui
|
|
|
|
}
|
|
catch (std::exception& ex)
|
|
{
|
|
LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());//TODO show err box and disable the tunn gui
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
class TunnelsPageUpdateListenerMainWindowImpl : public TunnelsPageUpdateListener {
|
|
MainWindow* mainWindow;
|
|
public:
|
|
TunnelsPageUpdateListenerMainWindowImpl(MainWindow* mainWindow_):mainWindow(mainWindow_){}
|
|
virtual void updated(std::string oldName, TunnelConfig* tunConf);
|
|
virtual void needsDeleting(std::string oldName);
|
|
};
|
|
|
|
TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener;
|
|
|
|
//void onLoggingOptionsChange() {}
|
|
|
|
SaverImpl* saverPtr;
|
|
};
|
|
|
|
#endif // MAINWINDOW_H
|