diff --git a/.gitignore b/.gitignore index c472d88e..5424262f 100644 --- a/.gitignore +++ b/.gitignore @@ -254,4 +254,11 @@ docs/generated build/Makefile # debian stuff -.pc/ \ No newline at end of file +.pc/ + +# qt + +qt/i2pd_qt/*.ui.autosave +qt/i2pd_qt/*.ui.bk* +qt/i2pd_qt/*.ui_* + diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml index 8c78e88b..0b8bef38 100755 --- a/android/res/values/strings.xml +++ b/android/res/values/strings.xml @@ -2,6 +2,8 @@ i2pd i2pd started + i2pd service started + i2pd service stopped Quit Graceful Quit Graceful quit is already in progress diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java index 5e0ac4d0..e1ebc269 100644 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java @@ -8,20 +8,20 @@ import android.util.Log; public class DaemonSingleton { private static final String TAG="i2pd"; private static final DaemonSingleton instance = new DaemonSingleton(); - public static interface StateChangeListener { void daemonStateChanged(); } - private final Set stateChangeListeners = new HashSet(); + public static interface StateUpdateListener { void daemonStateUpdate(); } + private final Set stateUpdateListeners = new HashSet(); public static DaemonSingleton getInstance() { return instance; } - public synchronized void addStateChangeListener(StateChangeListener listener) { stateChangeListeners.add(listener); } - public synchronized void removeStateChangeListener(StateChangeListener listener) { stateChangeListeners.remove(listener); } + public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } + public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } public synchronized void stopAcceptingTunnels() { if(isStartedOkay()){ state=State.gracefulShutdownInProgress; - fireStateChange(); + fireStateUpdate(); I2PD_JNI.stopAcceptingTunnels(); } } @@ -32,61 +32,63 @@ public class DaemonSingleton { private boolean startedOkay; - public static enum State {starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress}; + public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress}; - private State state = State.starting; + private State state = State.uninitialized; public State getState() { return state; } - { - synchronized(this){ - fireStateChange(); - new Thread(new Runnable(){ - - @Override - public void run() { - try { - I2PD_JNI.loadLibraries(); - synchronized (DaemonSingleton.this) { - state = State.jniLibraryLoaded; - fireStateChange(); - } - } catch (Throwable tr) { - lastThrowable=tr; - synchronized (DaemonSingleton.this) { - state = State.startFailed; - fireStateChange(); - } - return; + public synchronized void start() { + if(state != State.uninitialized)return; + state = State.starting; + fireStateUpdate(); + new Thread(new Runnable(){ + + @Override + public void run() { + try { + I2PD_JNI.loadLibraries(); + synchronized (DaemonSingleton.this) { + state = State.jniLibraryLoaded; + fireStateUpdate(); } - try { - synchronized (DaemonSingleton.this) { - daemonStartResult = I2PD_JNI.startDaemon(); - if("ok".equals(daemonStartResult)){state=State.startedOkay;setStartedOkay(true);} - else state=State.startFailed; - fireStateChange(); - } - } catch (Throwable tr) { - lastThrowable=tr; - synchronized (DaemonSingleton.this) { - state = State.startFailed; - fireStateChange(); - } - return; - } + } catch (Throwable tr) { + lastThrowable=tr; + synchronized (DaemonSingleton.this) { + state = State.startFailed; + fireStateUpdate(); + } + return; } - - }, "i2pdDaemonStart").start(); - } + try { + synchronized (DaemonSingleton.this) { + daemonStartResult = I2PD_JNI.startDaemon(); + if("ok".equals(daemonStartResult)){ + state=State.startedOkay; + setStartedOkay(true); + }else state=State.startFailed; + fireStateUpdate(); + } + } catch (Throwable tr) { + lastThrowable=tr; + synchronized (DaemonSingleton.this) { + state = State.startFailed; + fireStateUpdate(); + } + return; + } + } + + }, "i2pdDaemonStart").start(); } private Throwable lastThrowable; private String daemonStartResult="N/A"; - private synchronized void fireStateChange() { + private synchronized void fireStateUpdate() { Log.i(TAG, "daemon state change: "+state); - for(StateChangeListener listener : stateChangeListeners) { + for(StateUpdateListener listener : stateUpdateListeners) { try { - listener.daemonStateChanged(); + listener.daemonStateUpdate(); } catch (Throwable tr) { Log.e(TAG, "exception in listener ignored", tr); } diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index 16155651..d25d0a88 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -1,15 +1,17 @@ package org.purplei2p.i2pd; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; +import android.widget.Toast; public class ForegroundService extends Service { -// private NotificationManager mNM; + private NotificationManager notificationManager; // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. @@ -28,26 +30,31 @@ public class ForegroundService extends Service { @Override public void onCreate() { -// mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. We put an icon in the status bar. showNotification(); + daemon.start(); + // Tell the user we started. + Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("ForegroundService", "Received start id " + startId + ": " + intent); - return START_NOT_STICKY; + daemon.start(); + return START_STICKY; } @Override public void onDestroy() { // Cancel the persistent notification. - //mNM.cancel(NOTIFICATION); + notificationManager.cancel(NOTIFICATION); + stopForeground(true); // Tell the user we stopped. - //Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show(); } @Override @@ -84,4 +91,7 @@ public class ForegroundService extends Service { //mNM.notify(NOTIFICATION, notification); startForeground(NOTIFICATION, notification); } + + private final DaemonSingleton daemon = DaemonSingleton.getInstance(); } + diff --git a/android/src/org/purplei2p/i2pd/I2PD.java b/android/src/org/purplei2p/i2pd/I2PD.java index 0397cf03..86b877ac 100755 --- a/android/src/org/purplei2p/i2pd/I2PD.java +++ b/android/src/org/purplei2p/i2pd/I2PD.java @@ -22,12 +22,16 @@ import android.widget.Toast; public class I2PD extends Activity { private static final String TAG = "i2pd"; - private DaemonSingleton daemon = DaemonSingleton.getInstance(); - private DaemonSingleton.StateChangeListener daemonStateChangeListener = - new DaemonSingleton.StateChangeListener() { + + private TextView textView; + + private final DaemonSingleton daemon = DaemonSingleton.getInstance(); + + private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = + new DaemonSingleton.StateUpdateListener() { @Override - public void daemonStateChanged() { + public void daemonStateUpdate() { runOnUiThread(new Runnable(){ @Override @@ -50,19 +54,17 @@ public class I2PD extends Activity { } }; - private TextView textView; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - //set the app be foreground (do not unload when RAM needed) - doBindService(); - textView = new TextView(this); setContentView(textView); - daemonStateChangeListener.daemonStateChanged(); - daemon.addStateChangeListener(daemonStateChangeListener); + DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); + daemonStateUpdatedListener.daemonStateUpdate(); + + //set the app be foreground + doBindService(); } @Override @@ -73,7 +75,7 @@ public class I2PD extends Activity { private void localDestroy() { textView = null; - daemon.removeStateChangeListener(daemonStateChangeListener); + DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener); Timer gracefulQuitTimer = getGracefulQuitTimer(); if(gracefulQuitTimer!=null) { gracefulQuitTimer.cancel(); diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 309c0e9c..a0ec3e69 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -301,5 +301,19 @@ namespace config { return true; return false; } + + bool GetOptionAsAny(const char *name, boost::any& value) { + if (!m_Options.count(name)) + return false; + value = m_Options[name]; + return true; + } + + bool GetOptionAsAny(const std::string& name, boost::any& value) + { + return GetOptionAsAny (name.c_str (), value); + } + } // namespace config } // namespace i2p + diff --git a/libi2pd/Config.h b/libi2pd/Config.h index 1895da55..754618d7 100644 --- a/libi2pd/Config.h +++ b/libi2pd/Config.h @@ -84,6 +84,9 @@ namespace config { return GetOption (name.c_str (), value); } + bool GetOptionAsAny(const char *name, boost::any& value); + bool GetOptionAsAny(const std::string& name, boost::any& value); + /** * @brief Set value of given parameter * @param name Name of settable parameter diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 42968c7a..778e0745 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -24,22 +24,23 @@ namespace client SAMSocket::~SAMSocket () { - Terminate (); - } + Terminate ("~SAMSocket()"); + } - void SAMSocket::CloseStream () + void SAMSocket::CloseStream (const char* reason) { + LogPrint (eLogDebug, "SAMSocket::CloseStream, reason: ", reason); if (m_Stream) { m_Stream->Close (); m_Stream.reset (); - } - } - - void SAMSocket::Terminate () + } + } + + void SAMSocket::Terminate (const char* reason) { - CloseStream (); - + CloseStream (reason); + switch (m_SocketType) { case eSAMSocketTypeSession: @@ -82,7 +83,7 @@ namespace client { LogPrint (eLogError, "SAM: handshake read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - Terminate (); + Terminate ("SAM: handshake read error"); } else { @@ -130,7 +131,7 @@ namespace client else { LogPrint (eLogError, "SAM: handshake mismatch"); - Terminate (); + Terminate ("SAM: handshake mismatch"); } } } @@ -141,7 +142,7 @@ namespace client { LogPrint (eLogError, "SAM: handshake reply send error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - Terminate (); + Terminate ("SAM: handshake reply send error"); } else { @@ -153,6 +154,8 @@ namespace client void SAMSocket::SendMessageReply (const char * msg, size_t len, bool close) { + LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg); + if (!m_IsSilent) boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (), @@ -160,7 +163,7 @@ namespace client else { if (close) - Terminate (); + Terminate ("SAMSocket::SendMessageReply(close=true)"); else Receive (); } @@ -172,12 +175,12 @@ namespace client { LogPrint (eLogError, "SAM: reply send error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - Terminate (); + Terminate ("SAM: reply send error"); } else { if (close) - Terminate (); + Terminate ("SAMSocket::HandleMessageReplySent(close=true)"); else Receive (); } @@ -189,7 +192,7 @@ namespace client { LogPrint (eLogError, "SAM: read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - Terminate (); + Terminate ("SAM: read error"); } else if (m_SocketType == eSAMSocketTypeStream) HandleReceived (ecode, bytes_transferred); @@ -243,13 +246,13 @@ namespace client else { LogPrint (eLogError, "SAM: unexpected message ", m_Buffer); - Terminate (); + Terminate ("SAM: unexpected message"); } } else { LogPrint (eLogError, "SAM: malformed message ", m_Buffer); - Terminate (); + Terminate ("malformed message"); } } @@ -603,7 +606,7 @@ namespace client if (m_BufferOffset >= SAM_SOCKET_BUFFER_SIZE) { LogPrint (eLogError, "SAM: Buffer is full, terminate"); - Terminate (); + Terminate ("Buffer is full"); return; } m_Socket.async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset), @@ -617,7 +620,7 @@ namespace client { LogPrint (eLogError, "SAM: read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - Terminate (); + Terminate ("read error"); } else { @@ -631,8 +634,8 @@ namespace client { if (!ecode) s->Receive (); - else - s->m_Owner.GetService ().post ([s] { s->Terminate (); }); + else + s->m_Owner.GetService ().post ([s] { s->Terminate ("AsyncSend failed"); }); }); } } @@ -660,8 +663,8 @@ namespace client std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); } else // no more data - Terminate (); - } + Terminate ("no more data"); + } } } @@ -678,14 +681,14 @@ namespace client else { auto s = shared_from_this (); - m_Owner.GetService ().post ([s] { s->Terminate (); }); + m_Owner.GetService ().post ([s] { s->Terminate ("stream read error"); }); } } else { auto s = shared_from_this (); - m_Owner.GetService ().post ([s] { s->Terminate (); }); - } + m_Owner.GetService ().post ([s] { s->Terminate ("stream read error (op aborted)"); }); + } } else { @@ -700,7 +703,7 @@ namespace client { LogPrint (eLogError, "SAM: socket write error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - Terminate (); + Terminate ("socket write error at HandleWriteI2PData"); } else I2PReceive (); @@ -809,7 +812,7 @@ namespace client socks.push_back(sock); } } - for (auto & sock : socks ) sock->Terminate(); + for (auto & sock : socks ) sock->Terminate("SAMSession::CloseStreams()"); m_Sockets.clear(); } diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index d8a6ca1a..499f0da7 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -79,16 +79,17 @@ namespace client public: SAMSocket (SAMBridge& owner); - ~SAMSocket (); - void CloseStream (); // TODO: implement it better + ~SAMSocket (); + void CloseStream (const char* reason); // TODO: implement it better boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; void ReceiveHandshake (); void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; }; SAMSocketType GetSocketType () const { return m_SocketType; }; - void Terminate (); - private: + void Terminate (const char* reason); + + private: void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred); diff --git a/qt/i2pd_qt/ClientTunnelPane.cpp b/qt/i2pd_qt/ClientTunnelPane.cpp new file mode 100644 index 00000000..9fc00509 --- /dev/null +++ b/qt/i2pd_qt/ClientTunnelPane.cpp @@ -0,0 +1,199 @@ +#include "ClientTunnelPane.h" +#include "ClientContext.h" +#include "SignatureTypeComboboxFactory.h" +#include "QVBoxLayout" + +ClientTunnelPane::ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf): + TunnelPane(tunnelsPageUpdateListener, tunconf) {} + +void ClientTunnelPane::setGroupBoxTitle(const QString & title) { + clientTunnelNameGroupBox->setTitle(title); +} + +void ClientTunnelPane::deleteClientTunnelForm() { + delete clientTunnelNameGroupBox; + clientTunnelNameGroupBox=nullptr; + + //gridLayoutWidget_2->deleteLater(); + //gridLayoutWidget_2=nullptr; +} + +int ClientTunnelPane::appendClientTunnelForm( + ClientTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height) { + + ClientTunnelPane& ui = *this; + + clientTunnelNameGroupBox = new QGroupBox(tunnelsFormGridLayoutWidget); + clientTunnelNameGroupBox->setObjectName(QStringLiteral("clientTunnelNameGroupBox")); + + //tunnel + gridLayoutWidget_2 = new QWidget(clientTunnelNameGroupBox); + + QComboBox *tunnelTypeComboBox = new QComboBox(gridLayoutWidget_2); + tunnelTypeComboBox->setObjectName(QStringLiteral("tunnelTypeComboBox")); + tunnelTypeComboBox->addItem("Client", i2p::client::I2P_TUNNELS_SECTION_TYPE_CLIENT); + tunnelTypeComboBox->addItem("Socks", i2p::client::I2P_TUNNELS_SECTION_TYPE_SOCKS); + tunnelTypeComboBox->addItem("Websocks", i2p::client::I2P_TUNNELS_SECTION_TYPE_WEBSOCKS); + tunnelTypeComboBox->addItem("HTTP Proxy", i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTPPROXY); + tunnelTypeComboBox->addItem("UDP Client", i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPCLIENT); + + int h=(7+4)*60; + gridLayoutWidget_2->setGeometry(QRect(0, 0, 561, h)); + clientTunnelNameGroupBox->setGeometry(QRect(0, 0, 561, h)); + + { + const QString& type = tunnelConfig->getType(); + int index=0; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_CLIENT)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_SOCKS)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTPPROXY)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPCLIENT)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + } + + setupTunnelPane(tunnelConfig, + clientTunnelNameGroupBox, + gridLayoutWidget_2, tunnelTypeComboBox, + tunnelsFormGridLayoutWidget, tunnelsRow, height, h); + //this->tunnelGroupBox->setGeometry(QRect(0, tunnelsFormGridLayoutWidget->height()+10, 561, (7+5)*40+10)); + + /* + std::string destination; + */ + + //host + ui.horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.destinationLabel = new QLabel(gridLayoutWidget_2); + destinationLabel->setObjectName(QStringLiteral("destinationLabel")); + horizontalLayout_2->addWidget(destinationLabel); + ui.destinationLineEdit = new QLineEdit(gridLayoutWidget_2); + destinationLineEdit->setObjectName(QStringLiteral("destinationLineEdit")); + destinationLineEdit->setText(tunnelConfig->getdest().c_str()); + QObject::connect(destinationLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(destinationLineEdit); + ui.destinationHorizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(destinationHorizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + + /* + * int port; + */ + int gridIndex = 2; + { + int port = tunnelConfig->getport(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.portLabel = new QLabel(gridLayoutWidget_2); + portLabel->setObjectName(QStringLiteral("portLabel")); + horizontalLayout_2->addWidget(portLabel); + ui.portLineEdit = new QLineEdit(gridLayoutWidget_2); + portLineEdit->setObjectName(QStringLiteral("portLineEdit")); + portLineEdit->setText(QString::number(port)); + portLineEdit->setMaximumWidth(80); + QObject::connect(portLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(portLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + /* + * std::string keys; +*/ + { + std::string keys = tunnelConfig->getkeys(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.keysLabel = new QLabel(gridLayoutWidget_2); + keysLabel->setObjectName(QStringLiteral("keysLabel")); + horizontalLayout_2->addWidget(keysLabel); + ui.keysLineEdit = new QLineEdit(gridLayoutWidget_2); + keysLineEdit->setObjectName(QStringLiteral("keysLineEdit")); + keysLineEdit->setText(keys.c_str()); + QObject::connect(keysLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(keysLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + /* + * std::string address; + */ + { + std::string address = tunnelConfig->getaddress(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.addressLabel = new QLabel(gridLayoutWidget_2); + addressLabel->setObjectName(QStringLiteral("addressLabel")); + horizontalLayout_2->addWidget(addressLabel); + ui.addressLineEdit = new QLineEdit(gridLayoutWidget_2); + addressLineEdit->setObjectName(QStringLiteral("addressLineEdit")); + addressLineEdit->setText(address.c_str()); + QObject::connect(addressLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(addressLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + /* + int destinationPort; + i2p::data::SigningKeyType sigType; +*/ + { + int destinationPort = tunnelConfig->getdestinationPort(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.destinationPortLabel = new QLabel(gridLayoutWidget_2); + destinationPortLabel->setObjectName(QStringLiteral("destinationPortLabel")); + horizontalLayout_2->addWidget(destinationPortLabel); + ui.destinationPortLineEdit = new QLineEdit(gridLayoutWidget_2); + destinationPortLineEdit->setObjectName(QStringLiteral("destinationPortLineEdit")); + destinationPortLineEdit->setText(QString::number(destinationPort)); + destinationPortLineEdit->setMaximumWidth(80); + QObject::connect(destinationPortLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(destinationPortLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + i2p::data::SigningKeyType sigType = tunnelConfig->getsigType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.sigTypeLabel = new QLabel(gridLayoutWidget_2); + sigTypeLabel->setObjectName(QStringLiteral("sigTypeLabel")); + horizontalLayout_2->addWidget(sigTypeLabel); + ui.sigTypeComboBox = SignatureTypeComboBoxFactory::createSignatureTypeComboBox(gridLayoutWidget_2, sigType); + sigTypeComboBox->setObjectName(QStringLiteral("sigTypeComboBox")); + QObject::connect(sigTypeComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(sigTypeComboBox); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + I2CPParameters& i2cpParameters = tunnelConfig->getI2cpParameters(); + appendControlsForI2CPParameters(i2cpParameters, gridIndex); + } + + retranslateClientTunnelForm(ui); + + tunnelGridLayout->invalidate(); + + return h; +} + +ServerTunnelPane* ClientTunnelPane::asServerTunnelPane(){return nullptr;} +ClientTunnelPane* ClientTunnelPane::asClientTunnelPane(){return this;} diff --git a/qt/i2pd_qt/ClientTunnelPane.h b/qt/i2pd_qt/ClientTunnelPane.h new file mode 100644 index 00000000..16416cd8 --- /dev/null +++ b/qt/i2pd_qt/ClientTunnelPane.h @@ -0,0 +1,97 @@ +#ifndef CLIENTTUNNELPANE_H +#define CLIENTTUNNELPANE_H + +#include "QGridLayout" +#include "QVBoxLayout" + +#include "TunnelPane.h" + +class ClientTunnelConfig; + +class ServerTunnelPane; +class TunnelPane; + +class ClientTunnelPane : public TunnelPane { + Q_OBJECT +public: + ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf); + virtual ~ClientTunnelPane(){} + virtual ServerTunnelPane* asServerTunnelPane(); + virtual ClientTunnelPane* asClientTunnelPane(); + int appendClientTunnelForm(ClientTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, + int tunnelsRow, int height); + void deleteClientTunnelForm(); +private: + QGroupBox *clientTunnelNameGroupBox; + + //tunnel + QWidget *gridLayoutWidget_2; + + //destination + QHBoxLayout *horizontalLayout_2; + QLabel *destinationLabel; + QLineEdit *destinationLineEdit; + QSpacerItem *destinationHorizontalSpacer; + + //port + QLabel * portLabel; + QLineEdit * portLineEdit; + + //keys + QLabel * keysLabel; + QLineEdit * keysLineEdit; + + //address + QLabel * addressLabel; + QLineEdit * addressLineEdit; + + //destinationPort + QLabel * destinationPortLabel; + QLineEdit * destinationPortLineEdit; + + //sigType + QLabel * sigTypeLabel; + QComboBox * sigTypeComboBox; + +protected slots: + virtual void setGroupBoxTitle(const QString & title); + +private: + void retranslateClientTunnelForm(ClientTunnelPane& /*ui*/) { + typeLabel->setText(QApplication::translate("cltTunForm", "Client tunnel type:", 0)); + destinationLabel->setText(QApplication::translate("cltTunForm", "Destination:", 0)); + portLabel->setText(QApplication::translate("cltTunForm", "Port:", 0)); + keysLabel->setText(QApplication::translate("cltTunForm", "Keys:", 0)); + destinationPortLabel->setText(QApplication::translate("cltTunForm", "Destination port:", 0)); + addressLabel->setText(QApplication::translate("cltTunForm", "Address:", 0)); + sigTypeLabel->setText(QApplication::translate("cltTunForm", "Signature type:", 0)); + } +protected: + virtual bool applyDataFromUIToTunnelConfig() { + bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); + if(!ok)return false; + ClientTunnelConfig* ctc=tunnelConfig->asClientTunnelConfig(); + assert(ctc!=nullptr); + + //destination + ctc->setdest(destinationLineEdit->text().toStdString()); + + auto portStr=portLineEdit->text(); + int portInt=portStr.toInt(&ok); + if(!ok)return false; + ctc->setport(portInt); + + ctc->setkeys(keysLineEdit->text().toStdString()); + + ctc->setaddress(addressLineEdit->text().toStdString()); + + auto dportStr=portLineEdit->text(); + int dportInt=dportStr.toInt(&ok); + if(!ok)return false; + ctc->setdestinationPort(dportInt); + + ctc->setsigType(readSigTypeComboboxUI(sigTypeComboBox)); + } +}; + +#endif // CLIENTTUNNELPANE_H diff --git a/qt/i2pd_qt/DaemonQT.cpp b/qt/i2pd_qt/DaemonQT.cpp index 585bd56c..accd69b1 100644 --- a/qt/i2pd_qt/DaemonQT.cpp +++ b/qt/i2pd_qt/DaemonQT.cpp @@ -18,23 +18,41 @@ namespace qt void Worker::startDaemon() { qDebug("Performing daemon start..."); - m_Daemon.start(); - qDebug("Daemon started."); - emit resultReady(); + //try{ + m_Daemon.start(); + qDebug("Daemon started."); + emit resultReady(false, ""); + /*}catch(std::exception ex){ + emit resultReady(true, ex.what()); + }catch(...){ + emit resultReady(true, QObject::tr("Error: unknown exception")); + }*/ } void Worker::restartDaemon() { qDebug("Performing daemon restart..."); - m_Daemon.restart(); - qDebug("Daemon restarted."); - emit resultReady(); - } + //try{ + m_Daemon.restart(); + qDebug("Daemon restarted."); + emit resultReady(false, ""); + /*}catch(std::exception ex){ + emit resultReady(true, ex.what()); + }catch(...){ + emit resultReady(true, QObject::tr("Error: unknown exception")); + }*/ + } void Worker::stopDaemon() { qDebug("Performing daemon stop..."); - m_Daemon.stop(); - qDebug("Daemon stopped."); - emit resultReady(); - } + //try{ + m_Daemon.stop(); + qDebug("Daemon stopped."); + emit resultReady(false, ""); + /*}catch(std::exception ex){ + emit resultReady(true, ex.what()); + }catch(...){ + emit resultReady(true, QObject::tr("Error: unknown exception")); + }*/ + } Controller::Controller(DaemonQTImpl& daemon): m_Daemon (daemon) diff --git a/qt/i2pd_qt/DaemonQT.h b/qt/i2pd_qt/DaemonQT.h index 98e8b4e6..fc874f34 100644 --- a/qt/i2pd_qt/DaemonQT.h +++ b/qt/i2pd_qt/DaemonQT.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace i2p { @@ -32,6 +33,7 @@ namespace qt bool isRunning(); private: void setRunning(bool running); + void showError(std::string errorMsg); private: QMutex* mutex; bool m_IsRunning; @@ -55,7 +57,7 @@ namespace qt void stopDaemon(); signals: - void resultReady(); + void resultReady(bool failed, QString failureMessage); }; class Controller : public QObject @@ -69,7 +71,11 @@ namespace qt DaemonQTImpl& m_Daemon; public slots: - void handleResults(){} + void handleResults(bool failed, QString failureMessage){ + if(failed){ + QMessageBox::critical(0, QObject::tr("Error"), failureMessage); + } + } signals: void startDaemon(); void stopDaemon(); diff --git a/qt/i2pd_qt/MainWindowItems.cpp b/qt/i2pd_qt/MainWindowItems.cpp new file mode 100644 index 00000000..c1e1ab0a --- /dev/null +++ b/qt/i2pd_qt/MainWindowItems.cpp @@ -0,0 +1,2 @@ +#include "MainWindowItems.h" + diff --git a/qt/i2pd_qt/MainWindowItems.h b/qt/i2pd_qt/MainWindowItems.h new file mode 100644 index 00000000..a4be5fe0 --- /dev/null +++ b/qt/i2pd_qt/MainWindowItems.h @@ -0,0 +1,17 @@ +#ifndef MAINWINDOWITEMS_H +#define MAINWINDOWITEMS_H + +#include +#include +#include +#include +#include + +#include +#include + +#include "mainwindow.h" + +class MainWindow; + +#endif // MAINWINDOWITEMS_H diff --git a/qt/i2pd_qt/ServerTunnelPane.cpp b/qt/i2pd_qt/ServerTunnelPane.cpp new file mode 100644 index 00000000..d185be28 --- /dev/null +++ b/qt/i2pd_qt/ServerTunnelPane.cpp @@ -0,0 +1,275 @@ +#include "ServerTunnelPane.h" +#include "ClientContext.h" +#include "SignatureTypeComboboxFactory.h" + +ServerTunnelPane::ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf): + TunnelPane(tunnelsPageUpdateListener, tunconf) {} + +void ServerTunnelPane::setGroupBoxTitle(const QString & title) { + serverTunnelNameGroupBox->setTitle(title); +} + +int ServerTunnelPane::appendServerTunnelForm( + ServerTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height) { + + ServerTunnelPane& ui = *this; + + serverTunnelNameGroupBox = new QGroupBox(tunnelsFormGridLayoutWidget); + serverTunnelNameGroupBox->setObjectName(QStringLiteral("serverTunnelNameGroupBox")); + + //tunnel + gridLayoutWidget_2 = new QWidget(serverTunnelNameGroupBox); + + QComboBox *tunnelTypeComboBox = new QComboBox(gridLayoutWidget_2); + tunnelTypeComboBox->setObjectName(QStringLiteral("tunnelTypeComboBox")); + tunnelTypeComboBox->addItem("Server", i2p::client::I2P_TUNNELS_SECTION_TYPE_SERVER); + tunnelTypeComboBox->addItem("HTTP", i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTP); + tunnelTypeComboBox->addItem("IRC", i2p::client::I2P_TUNNELS_SECTION_TYPE_IRC); + tunnelTypeComboBox->addItem("UDP Server", i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPSERVER); + + int h=19*60; + gridLayoutWidget_2->setGeometry(QRect(0, 0, 561, h)); + serverTunnelNameGroupBox->setGeometry(QRect(0, 0, 561, h)); + + { + const QString& type = tunnelConfig->getType(); + int index=0; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_SERVER)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_HTTP)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_IRC)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + if(type==i2p::client::I2P_TUNNELS_SECTION_TYPE_UDPSERVER)tunnelTypeComboBox->setCurrentIndex(index); + ++index; + } + + setupTunnelPane(tunnelConfig, + serverTunnelNameGroupBox, + gridLayoutWidget_2, tunnelTypeComboBox, + tunnelsFormGridLayoutWidget, tunnelsRow, height, h); + //this->tunnelGroupBox->setGeometry(QRect(0, tunnelsFormGridLayoutWidget->height()+10, 561, 18*40+10)); + + //host + ui.horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.hostLabel = new QLabel(gridLayoutWidget_2); + hostLabel->setObjectName(QStringLiteral("hostLabel")); + horizontalLayout_2->addWidget(hostLabel); + ui.hostLineEdit = new QLineEdit(gridLayoutWidget_2); + hostLineEdit->setObjectName(QStringLiteral("hostLineEdit")); + hostLineEdit->setText(tunnelConfig->gethost().c_str()); + QObject::connect(hostLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(hostLineEdit); + ui.hostHorizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(hostHorizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + + int gridIndex = 2; + { + int port = tunnelConfig->getport(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.portLabel = new QLabel(gridLayoutWidget_2); + portLabel->setObjectName(QStringLiteral("portLabel")); + horizontalLayout_2->addWidget(portLabel); + ui.portLineEdit = new QLineEdit(gridLayoutWidget_2); + portLineEdit->setObjectName(QStringLiteral("portLineEdit")); + portLineEdit->setText(QString::number(port)); + portLineEdit->setMaximumWidth(80); + QObject::connect(portLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(portLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string keys = tunnelConfig->getkeys(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.keysLabel = new QLabel(gridLayoutWidget_2); + keysLabel->setObjectName(QStringLiteral("keysLabel")); + horizontalLayout_2->addWidget(keysLabel); + ui.keysLineEdit = new QLineEdit(gridLayoutWidget_2); + keysLineEdit->setObjectName(QStringLiteral("keysLineEdit")); + keysLineEdit->setText(keys.c_str()); + QObject::connect(keysLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(keysLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + int inPort = tunnelConfig->getinPort(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.inPortLabel = new QLabel(gridLayoutWidget_2); + inPortLabel->setObjectName(QStringLiteral("inPortLabel")); + horizontalLayout_2->addWidget(inPortLabel); + ui.inPortLineEdit = new QLineEdit(gridLayoutWidget_2); + inPortLineEdit->setObjectName(QStringLiteral("inPortLineEdit")); + inPortLineEdit->setText(QString::number(inPort)); + inPortLineEdit->setMaximumWidth(80); + QObject::connect(inPortLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(inPortLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string accessList = tunnelConfig->getaccessList(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.accessListLabel = new QLabel(gridLayoutWidget_2); + accessListLabel->setObjectName(QStringLiteral("accessListLabel")); + horizontalLayout_2->addWidget(accessListLabel); + ui.accessListLineEdit = new QLineEdit(gridLayoutWidget_2); + accessListLineEdit->setObjectName(QStringLiteral("accessListLineEdit")); + accessListLineEdit->setText(accessList.c_str()); + QObject::connect(accessListLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(accessListLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string hostOverride = tunnelConfig->gethostOverride(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.hostOverrideLabel = new QLabel(gridLayoutWidget_2); + hostOverrideLabel->setObjectName(QStringLiteral("hostOverrideLabel")); + horizontalLayout_2->addWidget(hostOverrideLabel); + ui.hostOverrideLineEdit = new QLineEdit(gridLayoutWidget_2); + hostOverrideLineEdit->setObjectName(QStringLiteral("hostOverrideLineEdit")); + hostOverrideLineEdit->setText(hostOverride.c_str()); + QObject::connect(hostOverrideLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(hostOverrideLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string webIRCPass = tunnelConfig->getwebircpass(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.webIRCPassLabel = new QLabel(gridLayoutWidget_2); + webIRCPassLabel->setObjectName(QStringLiteral("webIRCPassLabel")); + horizontalLayout_2->addWidget(webIRCPassLabel); + ui.webIRCPassLineEdit = new QLineEdit(gridLayoutWidget_2); + webIRCPassLineEdit->setObjectName(QStringLiteral("webIRCPassLineEdit")); + webIRCPassLineEdit->setText(webIRCPass.c_str()); + QObject::connect(webIRCPassLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(webIRCPassLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + bool gzip = tunnelConfig->getgzip(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.gzipCheckBox = new QCheckBox(gridLayoutWidget_2); + gzipCheckBox->setObjectName(QStringLiteral("gzipCheckBox")); + gzipCheckBox->setChecked(gzip); + QObject::connect(gzipCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(gzipCheckBox); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + i2p::data::SigningKeyType sigType = tunnelConfig->getsigType(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.sigTypeLabel = new QLabel(gridLayoutWidget_2); + sigTypeLabel->setObjectName(QStringLiteral("sigTypeLabel")); + horizontalLayout_2->addWidget(sigTypeLabel); + ui.sigTypeComboBox = SignatureTypeComboBoxFactory::createSignatureTypeComboBox(gridLayoutWidget_2, sigType); + sigTypeComboBox->setObjectName(QStringLiteral("sigTypeComboBox")); + QObject::connect(sigTypeComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(sigTypeComboBox); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + uint32_t maxConns = tunnelConfig->getmaxConns(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.maxConnsLabel = new QLabel(gridLayoutWidget_2); + maxConnsLabel->setObjectName(QStringLiteral("maxConnsLabel")); + horizontalLayout_2->addWidget(maxConnsLabel); + ui.maxConnsLineEdit = new QLineEdit(gridLayoutWidget_2); + maxConnsLineEdit->setObjectName(QStringLiteral("maxConnsLineEdit")); + maxConnsLineEdit->setText(QString::number(maxConns)); + maxConnsLineEdit->setMaximumWidth(80); + QObject::connect(maxConnsLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(maxConnsLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + std::string address = tunnelConfig->getaddress(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.addressLabel = new QLabel(gridLayoutWidget_2); + addressLabel->setObjectName(QStringLiteral("addressLabel")); + horizontalLayout_2->addWidget(addressLabel); + ui.addressLineEdit = new QLineEdit(gridLayoutWidget_2); + addressLineEdit->setObjectName(QStringLiteral("addressLineEdit")); + addressLineEdit->setText(address.c_str()); + QObject::connect(addressLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(addressLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + bool isUniqueLocal = tunnelConfig->getisUniqueLocal(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + ui.isUniqueLocalCheckBox = new QCheckBox(gridLayoutWidget_2); + isUniqueLocalCheckBox->setObjectName(QStringLiteral("isUniqueLocalCheckBox")); + isUniqueLocalCheckBox->setChecked(isUniqueLocal); + QObject::connect(gzipCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(isUniqueLocalCheckBox); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + I2CPParameters& i2cpParameters = tunnelConfig->getI2cpParameters(); + appendControlsForI2CPParameters(i2cpParameters, gridIndex); + } + + retranslateServerTunnelForm(ui); + + tunnelGridLayout->invalidate(); + + return h; +} + +void ServerTunnelPane::deleteServerTunnelForm() { + delete serverTunnelNameGroupBox;//->deleteLater(); + serverTunnelNameGroupBox=nullptr; + + //gridLayoutWidget_2->deleteLater(); + //gridLayoutWidget_2=nullptr; +} + + +ServerTunnelPane* ServerTunnelPane::asServerTunnelPane(){return this;} +ClientTunnelPane* ServerTunnelPane::asClientTunnelPane(){return nullptr;} diff --git a/qt/i2pd_qt/ServerTunnelPane.h b/qt/i2pd_qt/ServerTunnelPane.h new file mode 100644 index 00000000..a6994841 --- /dev/null +++ b/qt/i2pd_qt/ServerTunnelPane.h @@ -0,0 +1,161 @@ +#ifndef SERVERTUNNELPANE_H +#define SERVERTUNNELPANE_H + +#include "TunnelPane.h" +#include "TunnelsPageUpdateListener.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QVBoxLayout" +#include "QCheckBox" + +#include "assert.h" + +class ServerTunnelConfig; + +class ClientTunnelPane; + +class ServerTunnelPane : public TunnelPane { + Q_OBJECT + +public: + ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf); + virtual ~ServerTunnelPane(){} + + virtual ServerTunnelPane* asServerTunnelPane(); + virtual ClientTunnelPane* asClientTunnelPane(); + + int appendServerTunnelForm(ServerTunnelConfig* tunnelConfig, QWidget *tunnelsFormGridLayoutWidget, + int tunnelsRow, int height); + void deleteServerTunnelForm(); + +private: + QGroupBox *serverTunnelNameGroupBox; + + //tunnel + QWidget *gridLayoutWidget_2; + + //host + QHBoxLayout *horizontalLayout_2; + QLabel *hostLabel; + QLineEdit *hostLineEdit; + QSpacerItem *hostHorizontalSpacer; + + //port + QLabel * portLabel; + QLineEdit * portLineEdit; + + //keys + QLabel * keysLabel; + QLineEdit * keysLineEdit; + + //inPort + QLabel * inPortLabel; + QLineEdit * inPortLineEdit; + + //accessList + QLabel * accessListLabel; + QLineEdit * accessListLineEdit; + + //hostOverride + QLabel * hostOverrideLabel; + QLineEdit * hostOverrideLineEdit; + + //webIRCPass + QLabel * webIRCPassLabel; + QLineEdit * webIRCPassLineEdit; + + //address + QLabel * addressLabel; + QLineEdit * addressLineEdit; + + //maxConns + QLabel * maxConnsLabel; + QLineEdit * maxConnsLineEdit; + + //gzip + QCheckBox * gzipCheckBox; + + //isUniqueLocal + QCheckBox * isUniqueLocalCheckBox; + + //sigType + QLabel * sigTypeLabel; + QComboBox * sigTypeComboBox; + +protected slots: + virtual void setGroupBoxTitle(const QString & title); + +private: + void retranslateServerTunnelForm(ServerTunnelPane& /*ui*/) { + typeLabel->setText(QApplication::translate("srvTunForm", "Server tunnel type:", 0)); + hostLabel->setText(QApplication::translate("srvTunForm", "Host:", 0)); + portLabel->setText(QApplication::translate("srvTunForm", "Port:", 0)); + keysLabel->setText(QApplication::translate("srvTunForm", "Keys:", 0)); + inPortLabel->setText(QApplication::translate("srvTunForm", "InPort:", 0)); + accessListLabel->setText(QApplication::translate("srvTunForm", "Access list:", 0)); + hostOverrideLabel->setText(QApplication::translate("srvTunForm", "Host override:", 0)); + webIRCPassLabel->setText(QApplication::translate("srvTunForm", "WebIRC password:", 0)); + addressLabel->setText(QApplication::translate("srvTunForm", "Address:", 0)); + maxConnsLabel->setText(QApplication::translate("srvTunForm", "Max connections:", 0)); + + gzipCheckBox->setText(QApplication::translate("srvTunForm", "GZip", 0)); + isUniqueLocalCheckBox->setText(QApplication::translate("srvTunForm", "Is unique local", 0)); + + sigTypeLabel->setText(QApplication::translate("cltTunForm", "Signature type:", 0)); + } + +protected: + virtual bool applyDataFromUIToTunnelConfig() { + bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); + if(!ok)return false; + ServerTunnelConfig* stc=tunnelConfig->asServerTunnelConfig(); + assert(stc!=nullptr); + stc->sethost(hostLineEdit->text().toStdString()); + + auto portStr=portLineEdit->text(); + int portInt=portStr.toInt(&ok); + if(!ok)return false; + stc->setport(portInt); + + stc->setkeys(keysLineEdit->text().toStdString()); + + auto str=inPortLineEdit->text(); + int inPortInt=str.toInt(&ok); + if(!ok)return false; + stc->setinPort(inPortInt); + + stc->setaccessList(accessListLineEdit->text().toStdString()); + + stc->sethostOverride(hostOverrideLineEdit->text().toStdString()); + + stc->setwebircpass(webIRCPassLineEdit->text().toStdString()); + + stc->setaddress(addressLineEdit->text().toStdString()); + + auto mcStr=maxConnsLineEdit->text(); + uint32_t mcInt=(uint32_t)mcStr.toInt(&ok); + if(!ok)return false; + stc->setmaxConns(mcInt); + + stc->setgzip(gzipCheckBox->isChecked()); + + stc->setisUniqueLocal(isUniqueLocalCheckBox->isChecked()); + + stc->setsigType(readSigTypeComboboxUI(sigTypeComboBox)); + } +}; + +#endif // SERVERTUNNELPANE_H diff --git a/qt/i2pd_qt/SignatureTypeComboboxFactory.cpp b/qt/i2pd_qt/SignatureTypeComboboxFactory.cpp new file mode 100644 index 00000000..9313741a --- /dev/null +++ b/qt/i2pd_qt/SignatureTypeComboboxFactory.cpp @@ -0,0 +1,2 @@ +#include "SignatureTypeComboboxFactory.h" + diff --git a/qt/i2pd_qt/SignatureTypeComboboxFactory.h b/qt/i2pd_qt/SignatureTypeComboboxFactory.h new file mode 100644 index 00000000..4d2289e1 --- /dev/null +++ b/qt/i2pd_qt/SignatureTypeComboboxFactory.h @@ -0,0 +1,86 @@ +#ifndef SIGNATURETYPECOMBOBOXFACTORY_H +#define SIGNATURETYPECOMBOBOXFACTORY_H + +#include +#include +#include +#include "Identity.h" + +class SignatureTypeComboBoxFactory +{ + static const QVariant createUserData(const uint16_t sigType) { + return QVariant::fromValue((uint)sigType); + } + + static void addItem(QComboBox* signatureTypeCombobox, QString text, const uint16_t sigType) { + const QVariant userData = createUserData(sigType); + signatureTypeCombobox->addItem(text, userData); + } + +public: + static QComboBox* createSignatureTypeComboBox(QWidget* parent, uint16_t selectedSigType) { + QComboBox* signatureTypeCombobox = new QComboBox(parent); + /* + https://geti2p.net/spec/common-structures#certificate + все коды перечислены + это таблица "The defined Signing Public Key types are:" ? + да + + see also: Identity.h line 55 + */ + int index=0; + bool foundSelected=false; + + using namespace i2p::data; + + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "DSA_SHA1", 0), SIGNING_KEY_TYPE_DSA_SHA1); //0 + if(selectedSigType==SIGNING_KEY_TYPE_DSA_SHA1){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "ECDSA_SHA256_P256", 0), SIGNING_KEY_TYPE_ECDSA_SHA256_P256); //1 + if(selectedSigType==SIGNING_KEY_TYPE_ECDSA_SHA256_P256){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "ECDSA_SHA384_P384", 0), SIGNING_KEY_TYPE_ECDSA_SHA384_P384); //2 + if(selectedSigType==SIGNING_KEY_TYPE_ECDSA_SHA384_P384){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "ECDSA_SHA512_P521", 0), SIGNING_KEY_TYPE_ECDSA_SHA512_P521); //3 + if(selectedSigType==SIGNING_KEY_TYPE_ECDSA_SHA512_P521){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "RSA_SHA256_2048", 0), SIGNING_KEY_TYPE_RSA_SHA256_2048); //4 + if(selectedSigType==SIGNING_KEY_TYPE_RSA_SHA256_2048){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "RSA_SHA384_3072", 0), SIGNING_KEY_TYPE_RSA_SHA384_3072); //5 + if(selectedSigType==SIGNING_KEY_TYPE_RSA_SHA384_3072){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "RSA_SHA512_4096", 0), SIGNING_KEY_TYPE_RSA_SHA512_4096); //6 + if(selectedSigType==SIGNING_KEY_TYPE_RSA_SHA512_4096){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "EDDSA_SHA512_ED25519", 0), SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); //7 + if(selectedSigType==SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "EDDSA_SHA512_ED25519PH", 0), SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph); //8 + if(selectedSigType==SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + // the following signature type should never appear in netid=2 + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256", 0), SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256); //9 + if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_TC26_A_512_GOSTR3411_512", 0), SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512); //10 + if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + // TODO: remove later + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST", 0), SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST); //65281 + if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_TC26_A_512_GOSTR3411_512_TEST", 0), SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST); //65282 + if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} + ++index; + if(!foundSelected){ + addItem(signatureTypeCombobox, QString::number(selectedSigType), selectedSigType); //unknown sigtype + signatureTypeCombobox->setCurrentIndex(index); + } + + return signatureTypeCombobox; + } +}; + +#endif // SIGNATURETYPECOMBOBOXFACTORY_H diff --git a/qt/i2pd_qt/TunnelConfig.cpp b/qt/i2pd_qt/TunnelConfig.cpp new file mode 100644 index 00000000..0de17486 --- /dev/null +++ b/qt/i2pd_qt/TunnelConfig.cpp @@ -0,0 +1,41 @@ +#include "TunnelConfig.h" + +void TunnelConfig::saveHeaderToStringStream(std::stringstream& out) { + out << "[" << name << "]\n" + << "type=" << type.toStdString() << "\n"; +} + +void TunnelConfig::saveI2CPParametersToStringStream(std::stringstream& out) { + out << "inbound.length=" << i2cpParameters.getInbound_length().toStdString() << "\n" + << "outbound.length=" << i2cpParameters.getOutbound_length().toStdString() << "\n" + << "inbound.quantity=" << i2cpParameters.getInbound_quantity().toStdString() << "\n" + << "outbound.quantity=" << i2cpParameters.getOutbound_quantity().toStdString() << "\n" + << "crypto.tagsToSend=" << i2cpParameters.getCrypto_tagsToSend().toStdString() << "\n" + << "explicitPeers=" << i2cpParameters.getExplicitPeers().toStdString() << "\n\n"; +} + +void ClientTunnelConfig::saveToStringStream(std::stringstream& out) { + out << "address=" << address << "\n" + << "port=" << port << "\n" + << "destination=" << dest << "\n" + << "keys=" << keys << "\n" + << "destinationport=" << destinationPort << "\n" + << "signaturetype=" << sigType << "\n"; +} + + +void ServerTunnelConfig::saveToStringStream(std::stringstream& out) { + out << "host=" << host << "\n" + << "port=" << port << "\n" + << "keys=" << keys << "\n" + << "signaturetype=" << sigType << "\n" + << "inport=" << inPort << "\n" + << "accesslist=" << accessList << "\n" + << "gzip=" << (gzip?"true":"false") << "\n" + << "enableuniquelocal=" << (isUniqueLocal?"true":"false") << "\n" + << "address=" << address << "\n" + << "hostoverride=" << hostOverride << "\n" + << "webircpassword=" << webircpass << "\n" + << "maxconns=" << maxConns << "\n"; +} + diff --git a/qt/i2pd_qt/TunnelConfig.h b/qt/i2pd_qt/TunnelConfig.h new file mode 100644 index 00000000..b91a318c --- /dev/null +++ b/qt/i2pd_qt/TunnelConfig.h @@ -0,0 +1,230 @@ +#ifndef TUNNELCONFIG_H +#define TUNNELCONFIG_H + +#include "QString" +#include + +#include "../../libi2pd_client/ClientContext.h" +#include "TunnelsPageUpdateListener.h" + + +class I2CPParameters{ + QString inbound_length;//number of hops of an inbound tunnel. 3 by default; lower value is faster but dangerous + QString outbound_length;//number of hops of an outbound tunnel. 3 by default; lower value is faster but dangerous + QString inbound_quantity; //number of inbound tunnels. 5 by default + QString outbound_quantity; //number of outbound tunnels. 5 by default + QString crypto_tagsToSend; //number of ElGamal/AES tags to send. 40 by default; too low value may cause problems with tunnel building + QString explicitPeers; //list of comma-separated b64 addresses of peers to use, default: unset +public: + I2CPParameters(): inbound_length(), + outbound_length(), + inbound_quantity(), + outbound_quantity(), + crypto_tagsToSend(), + explicitPeers() {} + const QString& getInbound_length(){return inbound_length;} + const QString& getOutbound_length(){return outbound_length;} + const QString& getInbound_quantity(){return inbound_quantity;} + const QString& getOutbound_quantity(){return outbound_quantity;} + const QString& getCrypto_tagsToSend(){return crypto_tagsToSend;} + const QString& getExplicitPeers(){return explicitPeers;} + void setInbound_length(QString inbound_length_){inbound_length=inbound_length_;} + void setOutbound_length(QString outbound_length_){outbound_length=outbound_length_;} + void setInbound_quantity(QString inbound_quantity_){inbound_quantity=inbound_quantity_;} + void setOutbound_quantity(QString outbound_quantity_){outbound_quantity=outbound_quantity_;} + void setCrypto_tagsToSend(QString crypto_tagsToSend_){crypto_tagsToSend=crypto_tagsToSend_;} + void setExplicitPeers(QString explicitPeers_){explicitPeers=explicitPeers_;} +}; + + +class ClientTunnelConfig; +class ServerTunnelConfig; +class TunnelConfig { + /* + const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client"; + const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server"; + const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http"; + const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc"; + const char I2P_TUNNELS_SECTION_TYPE_UDPCLIENT[] = "udpclient"; + const char I2P_TUNNELS_SECTION_TYPE_UDPSERVER[] = "udpserver"; + const char I2P_TUNNELS_SECTION_TYPE_SOCKS[] = "socks"; + const char I2P_TUNNELS_SECTION_TYPE_WEBSOCKS[] = "websocks"; + const char I2P_TUNNELS_SECTION_TYPE_HTTPPROXY[] = "httpproxy"; + */ + QString type; + std::string name; +public: + TunnelConfig(std::string name_, QString& type_, I2CPParameters& i2cpParameters_): + type(type_), name(name_), i2cpParameters(i2cpParameters_) {} + virtual ~TunnelConfig(){} + const QString& getType(){return type;} + const std::string& getName(){return name;} + void setType(const QString& type_){type=type_;} + void setName(const std::string& name_){name=name_;} + I2CPParameters& getI2cpParameters(){return i2cpParameters;} + void saveHeaderToStringStream(std::stringstream& out); + void saveI2CPParametersToStringStream(std::stringstream& out); + virtual void saveToStringStream(std::stringstream& out)=0; + virtual ClientTunnelConfig* asClientTunnelConfig()=0; + virtual ServerTunnelConfig* asServerTunnelConfig()=0; + +private: + I2CPParameters i2cpParameters; +}; + +/* +# mandatory parameters: + std::string dest; + if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) + dest = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION); + int port = section.second.get (I2P_CLIENT_TUNNEL_PORT); +# optional parameters (may be omitted) + 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 destinationPort = section.second.get (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); +# * keys -- our identity, if unset, will be generated on every startup, +# if set and file missing, keys will be generated and placed to this file +# * address -- local interface to bind +# * signaturetype -- signature type for new destination. 0 (DSA/SHA1), 1 (EcDSA/SHA256) or 7 (EdDSA/SHA512) +[somelabel] +type = client +address = 127.0.0.1 +port = 6668 +destination = irc.postman.i2p +keys = irc-keys.dat +*/ +class ClientTunnelConfig : public TunnelConfig { + std::string dest; + int port; + std::string keys; + std::string address; + int destinationPort; + i2p::data::SigningKeyType sigType; +public: + ClientTunnelConfig(std::string name_, QString type_, I2CPParameters& i2cpParameters_, + std::string dest_, + int port_, + std::string keys_, + std::string address_, + int destinationPort_, + i2p::data::SigningKeyType sigType_): TunnelConfig(name_, type_, i2cpParameters_), + dest(dest_), + port(port_), + keys(keys_), + address(address_), + destinationPort(destinationPort_), + sigType(sigType_){} + std::string& getdest(){return dest;} + int getport(){return port;} + std::string & getkeys(){return keys;} + std::string & getaddress(){return address;} + int getdestinationPort(){return destinationPort;} + i2p::data::SigningKeyType getsigType(){return sigType;} + void setdest(const std::string& dest_){dest=dest_;} + void setport(int port_){port=port_;} + void setkeys(const std::string & keys_){keys=keys_;} + void setaddress(const std::string & address_){address=address_;} + void setdestinationPort(int destinationPort_){destinationPort=destinationPort_;} + void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;} + virtual void saveToStringStream(std::stringstream& out); + virtual ClientTunnelConfig* asClientTunnelConfig(){return this;} + virtual ServerTunnelConfig* asServerTunnelConfig(){return nullptr;} +}; + +/* +# mandatory parameters: +# * host -- ip address of our service +# * port -- port of our service +# * keys -- file with LeaseSet of address in i2p + std::string host = section.second.get (I2P_SERVER_TUNNEL_HOST); + int port = section.second.get (I2P_SERVER_TUNNEL_PORT); + std::string keys = section.second.get (I2P_SERVER_TUNNEL_KEYS); +# optional parameters (may be omitted) + 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 (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); + uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); + bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); +# * inport -- optional, i2p service port, if unset - the same as 'port' +# * accesslist -- comma-separated list of i2p addresses, allowed to connect +# every address is b32 without '.b32.i2p' part +[somelabel] +type = server +host = 127.0.0.1 +port = 6667 +keys = irc.dat +*/ +class ServerTunnelConfig : public TunnelConfig { + std::string host; + int port; + std::string keys; + int inPort; + std::string accessList; + std::string hostOverride; + std::string webircpass; + bool gzip; + i2p::data::SigningKeyType sigType; + uint32_t maxConns; + std::string address; + bool isUniqueLocal; +public: + ServerTunnelConfig(std::string name_, QString type_, I2CPParameters& i2cpParameters_, + std::string host_, + int port_, + std::string keys_, + int inPort_, + std::string accessList_, + std::string hostOverride_, + std::string webircpass_, + bool gzip_, + i2p::data::SigningKeyType sigType_, + uint32_t maxConns_, + std::string address_, + bool isUniqueLocal_): TunnelConfig(name_, type_, i2cpParameters_), + host(host_), + port(port_), + keys(keys_), + inPort(inPort_), + accessList(accessList_), + hostOverride(hostOverride_), + webircpass(webircpass_), + gzip(gzip_), + sigType(sigType_), + maxConns(maxConns_), + address(address_) {} + std::string& gethost(){return host;} + int getport(){return port;} + std::string& getkeys(){return keys;} + int getinPort(){return inPort;} + std::string& getaccessList(){return accessList;} + std::string& gethostOverride(){return hostOverride;} + std::string& getwebircpass(){return webircpass;} + bool getgzip(){return gzip;} + i2p::data::SigningKeyType getsigType(){return sigType;} + uint32_t getmaxConns(){return maxConns;} + std::string& getaddress(){return address;} + bool getisUniqueLocal(){return isUniqueLocal;} + void sethost(const std::string& host_){host=host_;} + void setport(int port_){port=port_;} + void setkeys(const std::string& keys_){keys=keys_;} + void setinPort(int inPort_){inPort=inPort_;} + void setaccessList(const std::string& accessList_){accessList=accessList_;} + void sethostOverride(const std::string& hostOverride_){hostOverride=hostOverride_;} + void setwebircpass(const std::string& webircpass_){webircpass=webircpass_;} + void setgzip(bool gzip_){gzip=gzip_;} + void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;} + void setmaxConns(uint32_t maxConns_){maxConns=maxConns_;} + void setaddress(const std::string& address_){address=address_;} + void setisUniqueLocal(bool isUniqueLocal_){isUniqueLocal=isUniqueLocal_;} + virtual void saveToStringStream(std::stringstream& out); + virtual ClientTunnelConfig* asClientTunnelConfig(){return nullptr;} + virtual ServerTunnelConfig* asServerTunnelConfig(){return this;} +}; + + +#endif // TUNNELCONFIG_H diff --git a/qt/i2pd_qt/TunnelPane.cpp b/qt/i2pd_qt/TunnelPane.cpp new file mode 100644 index 00000000..0dda5185 --- /dev/null +++ b/qt/i2pd_qt/TunnelPane.cpp @@ -0,0 +1,217 @@ +#include "TunnelPane.h" +#include "QMessageBox" + +TunnelPane::TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunnelConfig_): + QObject(), + tunnelConfig(tunnelConfig_), + tunnelsPageUpdateListener(tunnelsPageUpdateListener_), + gridLayoutWidget_2(nullptr) {} + +void TunnelPane::setupTunnelPane( + TunnelConfig* tunnelConfig, + QGroupBox *tunnelGroupBox, + QWidget* gridLayoutWidget_2, QComboBox * tunnelTypeComboBox, + QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height, int h) { + tunnelGroupBox->setGeometry(0, tunnelsFormGridLayoutWidget->height(), gridLayoutWidget_2->width(), h); + tunnelsFormGridLayoutWidget->resize(527, tunnelsFormGridLayoutWidget->height()+h); + + QObject::connect(tunnelTypeComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(updated())); + + + this->tunnelGroupBox=tunnelGroupBox; + + gridLayoutWidget_2->setObjectName(QStringLiteral("gridLayoutWidget_2")); + this->gridLayoutWidget_2=gridLayoutWidget_2; + tunnelGridLayout = new QVBoxLayout(gridLayoutWidget_2); + tunnelGridLayout->setObjectName(QStringLiteral("tunnelGridLayout")); + tunnelGridLayout->setContentsMargins(5, 5, 5, 5); + tunnelGridLayout->setSpacing(5); + + //header + QHBoxLayout *headerHorizontalLayout = new QHBoxLayout(); + headerHorizontalLayout->setObjectName(QStringLiteral("headerHorizontalLayout")); + + nameLabel = new QLabel(gridLayoutWidget_2); + nameLabel->setObjectName(QStringLiteral("nameLabel")); + headerHorizontalLayout->addWidget(nameLabel); + nameLineEdit = new QLineEdit(gridLayoutWidget_2); + nameLineEdit->setObjectName(QStringLiteral("nameLineEdit")); + const QString& tunnelName=tunnelConfig->getName().c_str(); + nameLineEdit->setText(tunnelName); + setGroupBoxTitle(tunnelName); + + QObject::connect(nameLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(setGroupBoxTitle(const QString &))); + QObject::connect(nameLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + + headerHorizontalLayout->addWidget(nameLineEdit); + headerHorizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + headerHorizontalLayout->addItem(headerHorizontalSpacer); + deletePushButton = new QPushButton(gridLayoutWidget_2); + deletePushButton->setObjectName(QStringLiteral("deletePushButton")); + QObject::connect(deletePushButton, SIGNAL(released()), + this, SLOT(deleteButtonReleased()));//MainWindow::DeleteTunnelNamed(std::string name) { + headerHorizontalLayout->addWidget(deletePushButton); + tunnelGridLayout->addLayout(headerHorizontalLayout); + + //type + { + const QString& type = tunnelConfig->getType(); + QHBoxLayout * horizontalLayout_ = new QHBoxLayout(); + horizontalLayout_->setObjectName(QStringLiteral("horizontalLayout_")); + typeLabel = new QLabel(gridLayoutWidget_2); + typeLabel->setObjectName(QStringLiteral("typeLabel")); + horizontalLayout_->addWidget(typeLabel); + horizontalLayout_->addWidget(tunnelTypeComboBox); + this->tunnelTypeComboBox=tunnelTypeComboBox; + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_); + } + + retranslateTunnelForm(*this); +} + +void TunnelPane::appendControlsForI2CPParameters(I2CPParameters& i2cpParameters, int& gridIndex) { + { + //number of hops of an inbound tunnel + const QString& inbound_length=i2cpParameters.getInbound_length(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + inbound_lengthLabel = new QLabel(gridLayoutWidget_2); + inbound_lengthLabel->setObjectName(QStringLiteral("inbound_lengthLabel")); + horizontalLayout_2->addWidget(inbound_lengthLabel); + inbound_lengthLineEdit = new QLineEdit(gridLayoutWidget_2); + inbound_lengthLineEdit->setObjectName(QStringLiteral("inbound_lengthLineEdit")); + inbound_lengthLineEdit->setText(inbound_length); + inbound_lengthLineEdit->setMaximumWidth(80); + QObject::connect(inbound_lengthLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(inbound_lengthLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of hops of an outbound tunnel + const QString& outbound_length=i2cpParameters.getOutbound_length(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + outbound_lengthLabel = new QLabel(gridLayoutWidget_2); + outbound_lengthLabel->setObjectName(QStringLiteral("outbound_lengthLabel")); + horizontalLayout_2->addWidget(outbound_lengthLabel); + outbound_lengthLineEdit = new QLineEdit(gridLayoutWidget_2); + outbound_lengthLineEdit->setObjectName(QStringLiteral("outbound_lengthLineEdit")); + outbound_lengthLineEdit->setText(outbound_length); + outbound_lengthLineEdit->setMaximumWidth(80); + QObject::connect(outbound_lengthLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(outbound_lengthLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of inbound tunnels + const QString& inbound_quantity=i2cpParameters.getInbound_quantity(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + inbound_quantityLabel = new QLabel(gridLayoutWidget_2); + inbound_quantityLabel->setObjectName(QStringLiteral("inbound_quantityLabel")); + horizontalLayout_2->addWidget(inbound_quantityLabel); + inbound_quantityLineEdit = new QLineEdit(gridLayoutWidget_2); + inbound_quantityLineEdit->setObjectName(QStringLiteral("inbound_quantityLineEdit")); + inbound_quantityLineEdit->setText(inbound_quantity); + inbound_quantityLineEdit->setMaximumWidth(80); + QObject::connect(inbound_quantityLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(inbound_quantityLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of outbound tunnels + const QString& outbound_quantity=i2cpParameters.getOutbound_quantity(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + outbound_quantityLabel = new QLabel(gridLayoutWidget_2); + outbound_quantityLabel->setObjectName(QStringLiteral("outbound_quantityLabel")); + horizontalLayout_2->addWidget(outbound_quantityLabel); + outbound_quantityLineEdit = new QLineEdit(gridLayoutWidget_2); + outbound_quantityLineEdit->setObjectName(QStringLiteral("outbound_quantityLineEdit")); + outbound_quantityLineEdit->setText(outbound_quantity); + outbound_quantityLineEdit->setMaximumWidth(80); + QObject::connect(outbound_quantityLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(outbound_quantityLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + { + //number of ElGamal/AES tags to send + const QString& crypto_tagsToSend=i2cpParameters.getCrypto_tagsToSend(); + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); + crypto_tagsToSendLabel = new QLabel(gridLayoutWidget_2); + crypto_tagsToSendLabel->setObjectName(QStringLiteral("crypto_tagsToSendLabel")); + horizontalLayout_2->addWidget(crypto_tagsToSendLabel); + crypto_tagsToSendLineEdit = new QLineEdit(gridLayoutWidget_2); + crypto_tagsToSendLineEdit->setObjectName(QStringLiteral("crypto_tagsToSendLineEdit")); + crypto_tagsToSendLineEdit->setText(crypto_tagsToSend); + crypto_tagsToSendLineEdit->setMaximumWidth(80); + QObject::connect(crypto_tagsToSendLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(updated())); + horizontalLayout_2->addWidget(crypto_tagsToSendLineEdit); + QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout_2->addItem(horizontalSpacer); + tunnelGridLayout->addLayout(horizontalLayout_2); + } + + retranslateI2CPParameters(); +} + +void TunnelPane::updated() { + std::string oldName=tunnelConfig->getName(); + if(!applyDataFromUIToTunnelConfig())return;//TODO visualise bad input + tunnelsPageUpdateListener->updated(oldName, tunnelConfig); +} + +void TunnelPane::deleteButtonReleased() { + QMessageBox msgBox; + msgBox.setText(QApplication::tr("Are you sure to delete this tunnel?")); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Cancel); + int ret = msgBox.exec(); + switch (ret) { + case QMessageBox::Ok: + // OK was clicked + tunnelsPageUpdateListener->needsDeleting(tunnelConfig->getName()); + break; + case QMessageBox::Cancel: + // Cancel was clicked + return; + } +} + +/* +const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client"; +const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server"; +const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http"; +const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc"; +const char I2P_TUNNELS_SECTION_TYPE_UDPCLIENT[] = "udpclient"; +const char I2P_TUNNELS_SECTION_TYPE_UDPSERVER[] = "udpserver"; +const char I2P_TUNNELS_SECTION_TYPE_SOCKS[] = "socks"; +const char I2P_TUNNELS_SECTION_TYPE_WEBSOCKS[] = "websocks"; +const char I2P_TUNNELS_SECTION_TYPE_HTTPPROXY[] = "httpproxy"; +*/ +QString TunnelPane::readTunnelTypeComboboxData() { + return tunnelTypeComboBox->currentData().toString(); +} + +i2p::data::SigningKeyType TunnelPane::readSigTypeComboboxUI(QComboBox* sigTypeComboBox) { + return (i2p::data::SigningKeyType) sigTypeComboBox->currentData().toInt(); +} diff --git a/qt/i2pd_qt/TunnelPane.h b/qt/i2pd_qt/TunnelPane.h new file mode 100644 index 00000000..d0a3d6a8 --- /dev/null +++ b/qt/i2pd_qt/TunnelPane.h @@ -0,0 +1,121 @@ +#ifndef TUNNELPANE_H +#define TUNNELPANE_H + +#include "QObject" +#include "QWidget" +#include "QComboBox" +#include "QGridLayout" +#include "QLabel" +#include "QPushButton" +#include "QApplication" +#include "QLineEdit" +#include "QGroupBox" +#include "QVBoxLayout" + +#include "TunnelConfig.h" + +class ServerTunnelPane; +class ClientTunnelPane; + +class TunnelConfig; +class I2CPParameters; + +class TunnelPane : public QObject { + + Q_OBJECT + +public: + TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunconf); + virtual ~TunnelPane(){} + + virtual ServerTunnelPane* asServerTunnelPane()=0; + virtual ClientTunnelPane* asClientTunnelPane()=0; + +protected: + TunnelConfig* tunnelConfig; + TunnelsPageUpdateListener* tunnelsPageUpdateListener; + QVBoxLayout *tunnelGridLayout; + QGroupBox *tunnelGroupBox; + QWidget* gridLayoutWidget_2; + + //header + QLabel *nameLabel; + QLineEdit *nameLineEdit; +public: + QLineEdit * getNameLineEdit() { return nameLineEdit; } + +public slots: + void updated(); + void deleteButtonReleased(); + +protected: + QSpacerItem *headerHorizontalSpacer; + QPushButton *deletePushButton; + + //type + QComboBox *tunnelTypeComboBox; + QLabel *typeLabel; + + //i2cp + + QLabel * inbound_lengthLabel; + QLineEdit * inbound_lengthLineEdit; + + QLabel * outbound_lengthLabel; + QLineEdit * outbound_lengthLineEdit; + + QLabel * inbound_quantityLabel; + QLineEdit * inbound_quantityLineEdit; + + QLabel * outbound_quantityLabel; + QLineEdit * outbound_quantityLineEdit; + + QLabel * crypto_tagsToSendLabel; + QLineEdit * crypto_tagsToSendLineEdit; + + QString readTunnelTypeComboboxData(); + + //should be created by factory + i2p::data::SigningKeyType readSigTypeComboboxUI(QComboBox* sigTypeComboBox); + + //returns false when invalid data at UI + virtual bool applyDataFromUIToTunnelConfig() { + tunnelConfig->setName(nameLineEdit->text().toStdString()); + tunnelConfig->setType(readTunnelTypeComboboxData()); + I2CPParameters& i2cpParams=tunnelConfig->getI2cpParameters(); + i2cpParams.setInbound_length(inbound_lengthLineEdit->text()); + i2cpParams.setInbound_quantity(inbound_quantityLineEdit->text()); + i2cpParams.setOutbound_length(outbound_lengthLineEdit->text()); + i2cpParams.setOutbound_quantity(outbound_quantityLineEdit->text()); + i2cpParams.setCrypto_tagsToSend(crypto_tagsToSendLineEdit->text()); + } + + void setupTunnelPane( + TunnelConfig* tunnelConfig, + QGroupBox *tunnelGroupBox, + QWidget* gridLayoutWidget_2, QComboBox * tunnelTypeComboBox, + QWidget *tunnelsFormGridLayoutWidget, int tunnelsRow, int height, int h); + void appendControlsForI2CPParameters(I2CPParameters& i2cpParameters, int& gridIndex); +public: + int height() { + return gridLayoutWidget_2?gridLayoutWidget_2->height():0; + } + +protected slots: + virtual void setGroupBoxTitle(const QString & title)=0; +private: + void retranslateTunnelForm(TunnelPane& ui) { + ui.deletePushButton->setText(QApplication::translate("tunForm", "Delete Tunnel", 0)); + ui.nameLabel->setText(QApplication::translate("tunForm", "Tunnel name:", 0)); + } + + void retranslateI2CPParameters() { + inbound_lengthLabel->setText(QApplication::translate("tunForm", "Number of hops of an inbound tunnel:", 0));; + outbound_lengthLabel->setText(QApplication::translate("tunForm", "Number of hops of an outbound tunnel:", 0));; + inbound_quantityLabel->setText(QApplication::translate("tunForm", "Number of inbound tunnels:", 0));; + outbound_quantityLabel->setText(QApplication::translate("tunForm", "Number of outbound tunnels:", 0));; + crypto_tagsToSendLabel->setText(QApplication::translate("tunForm", "Number of ElGamal/AES tags to send:", 0));; + } +}; + +#endif // TUNNELPANE_H diff --git a/qt/i2pd_qt/TunnelsPageUpdateListener.h b/qt/i2pd_qt/TunnelsPageUpdateListener.h new file mode 100644 index 00000000..83b4e9fe --- /dev/null +++ b/qt/i2pd_qt/TunnelsPageUpdateListener.h @@ -0,0 +1,12 @@ +#ifndef TUNNELSPAGEUPDATELISTENER_H +#define TUNNELSPAGEUPDATELISTENER_H + +class TunnelConfig; + +class TunnelsPageUpdateListener { +public: + virtual void updated(std::string oldName, TunnelConfig* tunConf)=0; + virtual void needsDeleting(std::string oldName)=0; +}; + +#endif // TUNNELSPAGEUPDATELISTENER_H diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 229d3f2e..66839ff5 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -24,60 +24,170 @@ IFADDRS_PATH = $$MAIN_PATH/android-ifaddrs # 2) Check API 11 # Finally, click Install. -SOURCES += DaemonQT.cpp mainwindow.cpp -# ../../HTTPServer.cpp ../../I2PControl.cpp ../../Daemon.cpp ../../Config.cpp \ -# ../../AddressBook.cpp ../../api.cpp ../../Base.cpp ../../BOB.cpp ../../ClientContext.cpp \ -# ../../Crypto.cpp ../../Datagram.cpp ../../Destination.cpp ../../Family.cpp ../../FS.cpp \ -# ../../Garlic.cpp ../../HTTP.cpp ../../HTTPProxy.cpp ../../I2CP.cpp ../../I2NPProtocol.cpp \ -# ../../I2PEndian.cpp ../../I2PService.cpp ../../I2PTunnel.cpp ../../Identity.cpp \ -# ../../LeaseSet.cpp ../../Log.cpp ../../NetDb.cpp ../../NetDbRequests.cpp \ -# ../../NTCPSession.cpp ../../Profiling.cpp ../../Reseed.cpp ../../RouterContext.cpp \ -# ../../RouterInfo.cpp ../../SAM.cpp ../../Signature.cpp ../../SOCKS.cpp ../../SSU.cpp \ -# ../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \ -# ../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \ -# ../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.cpp \ -# ../../Event.cpp ../../BloomFiler.cpp ../../Gost.cpp ../../MatchedDestination.cpp \ -# ../../i2pd.cpp +SOURCES += DaemonQT.cpp mainwindow.cpp \ + ../../libi2pd/api.cpp \ + ../../libi2pd/Base.cpp \ + ../../libi2pd/BloomFilter.cpp \ + ../../libi2pd/Config.cpp \ + ../../libi2pd/Crypto.cpp \ + ../../libi2pd/Datagram.cpp \ + ../../libi2pd/Destination.cpp \ + ../../libi2pd/Event.cpp \ + ../../libi2pd/Family.cpp \ + ../../libi2pd/FS.cpp \ + ../../libi2pd/Garlic.cpp \ + ../../libi2pd/Gost.cpp \ + ../../libi2pd/Gzip.cpp \ + ../../libi2pd/HTTP.cpp \ + ../../libi2pd/I2NPProtocol.cpp \ + ../../libi2pd/I2PEndian.cpp \ + ../../libi2pd/Identity.cpp \ + ../../libi2pd/LeaseSet.cpp \ + ../../libi2pd/Log.cpp \ + ../../libi2pd/NetDb.cpp \ + ../../libi2pd/NetDbRequests.cpp \ + ../../libi2pd/NTCPSession.cpp \ + ../../libi2pd/Profiling.cpp \ + ../../libi2pd/Reseed.cpp \ + ../../libi2pd/RouterContext.cpp \ + ../../libi2pd/RouterInfo.cpp \ + ../../libi2pd/Signature.cpp \ + ../../libi2pd/SSU.cpp \ + ../../libi2pd/SSUData.cpp \ + ../../libi2pd/SSUSession.cpp \ + ../../libi2pd/Streaming.cpp \ + ../../libi2pd/Timestamp.cpp \ + ../../libi2pd/TransitTunnel.cpp \ + ../../libi2pd/Transports.cpp \ + ../../libi2pd/Tunnel.cpp \ + ../../libi2pd/TunnelEndpoint.cpp \ + ../../libi2pd/TunnelGateway.cpp \ + ../../libi2pd/TunnelPool.cpp \ + ../../libi2pd/util.cpp \ + ../../libi2pd_client/AddressBook.cpp \ + ../../libi2pd_client/BOB.cpp \ + ../../libi2pd_client/ClientContext.cpp \ + ../../libi2pd_client/HTTPProxy.cpp \ + ../../libi2pd_client/I2CP.cpp \ + ../../libi2pd_client/I2PService.cpp \ + ../../libi2pd_client/I2PTunnel.cpp \ + ../../libi2pd_client/MatchedDestination.cpp \ + ../../libi2pd_client/SAM.cpp \ + ../../libi2pd_client/SOCKS.cpp \ + ../../libi2pd_client/Websocket.cpp \ + ../../libi2pd_client/WebSocks.cpp \ + ClientTunnelPane.cpp \ + MainWindowItems.cpp \ + ServerTunnelPane.cpp \ + SignatureTypeComboboxFactory.cpp \ + TunnelConfig.cpp \ + TunnelPane.cpp \ + ../../daemon/Daemon.cpp \ + ../../daemon/HTTPServer.cpp \ + ../../daemon/i2pd.cpp \ + ../../daemon/I2PControl.cpp \ + ../../daemon/UnixDaemon.cpp \ + ../../daemon/UPnP.cpp -SOURCES += $$files(../../libi2pd/*.cpp) -SOURCES += $$files(../../libi2pd_client/*.cpp) -SOURCES += $$files(../../daemon/*.cpp) +#qt creator does not handle this well +#SOURCES += $$files(../../libi2pd/*.cpp) +#SOURCES += $$files(../../libi2pd_client/*.cpp) +#SOURCES += $$files(../../daemon/*.cpp) +#SOURCES += $$files(./*.cpp) SOURCES -= ../../daemon/UnixDaemon.cpp -HEADERS += DaemonQT.h mainwindow.h -# ../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \ -# ../../AddressBook.h ../../api.h ../../Base.h ../../BOB.h ../../ClientContext.h \ -# ../../Crypto.h ../../Datagram.h ../../Destination.h ../../Family.h ../../FS.h \ -# ../../Garlic.h ../../HTTP.h ../../HTTPProxy.h ../../I2CP.h ../../I2NPProtocol.h \ -# ../../I2PEndian.h ../../I2PService.h ../../I2PTunnel.h ../../Identity.h ../../LeaseSet.h \ -# ../../LittleBigEndian.h ../../Log.h ../../NetDb.h ../../NetDbRequests.h ../../NTCPSession.h \ -# ../../Profiling.h ../../Queue.h ../../Reseed.h ../../RouterContext.h ../../RouterInfo.h \ -# ../../SAM.h ../../Signature.h ../../SOCKS.h ../../SSU.h ../../SSUData.h ../../SSUSession.h \ -# ../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \ -# ../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \ -# ../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \ -# ../../util.h ../../version.h ../../Gzip.h ../../Tag.h \ -# ../../BloomFiler.h ../../Event.h ../../Gost.h ../../MatchedDestination.h +HEADERS += DaemonQT.h mainwindow.h \ + ../../libi2pd/api.h \ + ../../libi2pd/Base.h \ + ../../libi2pd/BloomFilter.h \ + ../../libi2pd/Config.h \ + ../../libi2pd/Crypto.h \ + ../../libi2pd/Datagram.h \ + ../../libi2pd/Destination.h \ + ../../libi2pd/Event.h \ + ../../libi2pd/Family.h \ + ../../libi2pd/FS.h \ + ../../libi2pd/Garlic.h \ + ../../libi2pd/Gost.h \ + ../../libi2pd/Gzip.h \ + ../../libi2pd/HTTP.h \ + ../../libi2pd/I2NPProtocol.h \ + ../../libi2pd/I2PEndian.h \ + ../../libi2pd/Identity.h \ + ../../libi2pd/LeaseSet.h \ + ../../libi2pd/LittleBigEndian.h \ + ../../libi2pd/Log.h \ + ../../libi2pd/NetDb.hpp \ + ../../libi2pd/NetDbRequests.h \ + ../../libi2pd/NTCPSession.h \ + ../../libi2pd/Profiling.h \ + ../../libi2pd/Queue.h \ + ../../libi2pd/Reseed.h \ + ../../libi2pd/RouterContext.h \ + ../../libi2pd/RouterInfo.h \ + ../../libi2pd/Signature.h \ + ../../libi2pd/SSU.h \ + ../../libi2pd/SSUData.h \ + ../../libi2pd/SSUSession.h \ + ../../libi2pd/Streaming.h \ + ../../libi2pd/Tag.h \ + ../../libi2pd/Timestamp.h \ + ../../libi2pd/TransitTunnel.h \ + ../../libi2pd/Transports.h \ + ../../libi2pd/TransportSession.h \ + ../../libi2pd/Tunnel.h \ + ../../libi2pd/TunnelBase.h \ + ../../libi2pd/TunnelConfig.h \ + ../../libi2pd/TunnelEndpoint.h \ + ../../libi2pd/TunnelGateway.h \ + ../../libi2pd/TunnelPool.h \ + ../../libi2pd/util.h \ + ../../libi2pd/version.h \ + ../../libi2pd_client/AddressBook.h \ + ../../libi2pd_client/BOB.h \ + ../../libi2pd_client/ClientContext.h \ + ../../libi2pd_client/HTTPProxy.h \ + ../../libi2pd_client/I2CP.h \ + ../../libi2pd_client/I2PService.h \ + ../../libi2pd_client/I2PTunnel.h \ + ../../libi2pd_client/MatchedDestination.h \ + ../../libi2pd_client/SAM.h \ + ../../libi2pd_client/SOCKS.h \ + ../../libi2pd_client/Websocket.h \ + ../../libi2pd_client/WebSocks.h \ + ClientTunnelPane.h \ + MainWindowItems.h \ + ServerTunnelPane.h \ + SignatureTypeComboboxFactory.h \ + TunnelConfig.h \ + TunnelPane.h \ + TunnelsPageUpdateListener.h \ + ../../daemon/Daemon.h \ + ../../daemon/HTTPServer.h \ + ../../daemon/I2PControl.h \ + ../../daemon/UPnP.h INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client INCLUDEPATH += ../../daemon +INCLUDEPATH += . -FORMS += mainwindow.ui - -CONFIG += mobility - -MOBILITY = +FORMS += mainwindow.ui \ + tunnelform.ui LIBS += -lz android { message("Using Android settings") - DEFINES += ANDROID=1 + DEFINES += ANDROID=1 DEFINES += __ANDROID__ - INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ + CONFIG += mobility + + MOBILITY = + + INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ $$OPENSSL_PATH/openssl-1.0.2/include \ $$MINIUPNP_PATH/miniupnp-2.0/include \ $$IFADDRS_PATH @@ -138,3 +248,4 @@ linux:!android { QT += xml #INSTALLS += sources } + diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 4b749473..304a3758 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -1,63 +1,214 @@ #include "mainwindow.h" -//#include "ui_mainwindow.h" +#include "ui_mainwindow.h" #include #include +#include +#include #include "RouterContext.h" +#include "Config.h" +#include "FS.h" +#include "Log.h" + #ifndef ANDROID -#include +# include #endif +#include + +#include + +std::string programOptionsWriterCurrentSection; + MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent)/*, - ui(new Ui::MainWindow)*/ + QMainWindow(parent) #ifndef ANDROID ,quitting(false) #endif + ,ui(new Ui::MainWindow) + ,configItems() + ,datadir() + ,confpath() + ,tunconfpath() + ,tunnelsPageUpdateListener(this) + { - //ui->setupUi(this); - if (objectName().isEmpty()) - setObjectName(QStringLiteral("MainWindow")); - resize(800, 480); - centralWidget = new QWidget(this); - centralWidget->setObjectName(QStringLiteral("centralWidget")); - verticalLayoutWidget = new QWidget(centralWidget); - verticalLayoutWidget->setObjectName(QStringLiteral("verticalLayoutWidget")); - //verticalLayoutWidget->setGeometry(QRect(10, 20, 771, 441)); - verticalLayout1 = new QVBoxLayout(verticalLayoutWidget); - verticalLayout1->setSpacing(6); - verticalLayout1->setContentsMargins(11, 11, 11, 11); - verticalLayout1->setObjectName(QStringLiteral("verticalLayout1")); - verticalLayout1->setContentsMargins(0, 0, 0, 0); - quitButton = new QPushButton(verticalLayoutWidget); - quitButton->setObjectName(QStringLiteral("quitButton")); - QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - sizePolicy.setHorizontalStretch(1); - //sizePolicy.setVerticalStretch(1); - sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth()); - quitButton->setSizePolicy(sizePolicy); - verticalLayout1->addWidget(quitButton); - gracefulQuitButton = new QPushButton(verticalLayoutWidget); - gracefulQuitButton->setObjectName(QStringLiteral("gracefulQuitButton")); - QSizePolicy sizePolicy2(QSizePolicy::Maximum, QSizePolicy::Maximum); - sizePolicy2.setHorizontalStretch(1); - //sizePolicy2.setVerticalStretch(1); - sizePolicy2.setHeightForWidth(gracefulQuitButton->sizePolicy().hasHeightForWidth()); - gracefulQuitButton->setSizePolicy(sizePolicy2); - verticalLayout1->addWidget(gracefulQuitButton); + ui->setupUi(this); + setWindowTitle(QApplication::translate("AppTitle","I2PD")); - setCentralWidget(centralWidget); + //TODO handle resizes and change the below into resize() call + setFixedSize(width(), 480); + ui->centralWidget->setMinimumHeight(480); + ui->centralWidget->setMaximumHeight(480); + onResize(); - setWindowTitle(QApplication::translate("MainWindow", "i2pd", 0)); - quitButton->setText(QApplication::translate("MainWindow", "Quit", 0)); - gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful Quit", 0)); + ui->stackedWidget->setCurrentIndex(0); + ui->settingsScrollArea->resize(ui->settingsContentsGridLayout->sizeHint().width()+10,380); + QScrollBar* const barSett = ui->settingsScrollArea->verticalScrollBar(); + //QSize szSettContents = ui->settingsContentsGridLayout->minimumSize(); + int w = 683; + int h = 3060; + ui->settingsContents->setFixedSize(w, h); + //ui->settingsContents->resize(w, h); + //ui->settingsContents->adjustSize(); + + /* + QPalette pal(palette()); + pal.setColor(QPalette::Background, Qt::red); + ui->settingsContents->setAutoFillBackground(true); + ui->settingsContents->setPalette(pal); + */ + + //ui->settingsScrollArea->adjustSize(); + /*ui->tunnelsScrollAreaWidgetContents->setFixedSize( + ui->tunnelsScrollArea->width() - barSett->width(), 0);*/ #ifndef ANDROID createActions(); createTrayIcon(); #endif - QObject::connect(quitButton, SIGNAL(released()), this, SLOT(handleQuitButton())); - QObject::connect(gracefulQuitButton, SIGNAL(released()), this, SLOT(handleGracefulQuitButton())); + QObject::connect(ui->statusPagePushButton, SIGNAL(released()), this, SLOT(showStatusPage())); + QObject::connect(ui->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage())); + + QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage())); + QObject::connect(ui->restartPagePushButton, SIGNAL(released()), this, SLOT(showRestartPage())); + QObject::connect(ui->quitPagePushButton, SIGNAL(released()), this, SLOT(showQuitPage())); + + QObject::connect(ui->fastQuitPushButton, SIGNAL(released()), this, SLOT(handleQuitButton())); + QObject::connect(ui->gracefulQuitPushButton, SIGNAL(released()), this, SLOT(handleGracefulQuitButton())); + +# define OPTION(section,option,defaultValueGetter) ConfigOption(QString(section),QString(option)) + + initFileChooser( OPTION("","conf",[](){return "";}), ui->configFileLineEdit, ui->configFileBrowsePushButton); + initFolderChooser( OPTION("","datadir",[]{return "";}), ui->dataFolderLineEdit, ui->dataFolderBrowsePushButton); + initFileChooser( OPTION("","tunconf",[](){return "";}), ui->tunnelsConfigFileLineEdit, ui->tunnelsConfigFileBrowsePushButton); + + initFileChooser( OPTION("","pidfile",[]{return "";}), ui->pidFileLineEdit, ui->pidFileBrowsePushButton); + logOption=initNonGUIOption( OPTION("","log",[]{return "";})); + daemonOption=initNonGUIOption( OPTION("","daemon",[]{return "";})); + serviceOption=initNonGUIOption( OPTION("","service",[]{return "";})); + + logFileNameOption=initFileChooser( OPTION("","logfile",[]{return "";}), ui->logFileLineEdit, ui->logFileBrowsePushButton); + initLogLevelCombobox(OPTION("","loglevel",[]{return "";}), ui->logLevelComboBox); + + initIPAddressBox( OPTION("","host",[]{return "";}), ui->routerExternalHostLineEdit, tr("Router external address -> Host")); + initTCPPortBox( OPTION("","port",[]{return "";}), ui->routerExternalPortLineEdit, tr("Router external address -> Port")); + + initCheckBox( OPTION("","ipv6",[]{return "false";}), ui->ipv6CheckBox); + initCheckBox( OPTION("","notransit",[]{return "false";}), ui->notransitCheckBox); + initCheckBox( OPTION("","floodfill",[]{return "false";}), ui->floodfillCheckBox); + initStringBox( OPTION("","bandwidth",[]{return "";}), ui->bandwidthLineEdit); + initStringBox( OPTION("","family",[]{return "";}), ui->familyLineEdit); + initIntegerBox( OPTION("","netid",[]{return "2";}), ui->netIdLineEdit, tr("NetID")); + +#ifdef Q_OS_WIN + initCheckBox( OPTION("","insomnia",[]{return "";}), ui->insomniaCheckBox); + initNonGUIOption( OPTION("","svcctl",[]{return "";})); + initNonGUIOption( OPTION("","close",[]{return "";})); +#else + ui->insomniaCheckBox->setEnabled(false); +#endif + + initCheckBox( OPTION("http","enabled",[]{return "true";}), ui->webconsoleEnabledCheckBox); + initIPAddressBox( OPTION("http","address",[]{return "";}), ui->webconsoleAddrLineEdit, tr("HTTP webconsole -> IP address")); + initTCPPortBox( OPTION("http","port",[]{return "7070";}), ui->webconsolePortLineEdit, tr("HTTP webconsole -> Port")); + initCheckBox( OPTION("http","auth",[]{return "";}), ui->webconsoleBasicAuthCheckBox); + initStringBox( OPTION("http","user",[]{return "i2pd";}), ui->webconsoleUserNameLineEditBasicAuth); + initStringBox( OPTION("http","pass",[]{return "";}), ui->webconsolePasswordLineEditBasicAuth); + + initCheckBox( OPTION("httpproxy","enabled",[]{return "";}), ui->httpProxyEnabledCheckBox); + initIPAddressBox( OPTION("httpproxy","address",[]{return "";}), ui->httpProxyAddressLineEdit, tr("HTTP proxy -> IP address")); + initTCPPortBox( OPTION("httpproxy","port",[]{return "4444";}), ui->httpProxyPortLineEdit, tr("HTTP proxy -> Port")); + initFileChooser( OPTION("httpproxy","keys",[]{return "";}), ui->httpProxyKeyFileLineEdit, ui->httpProxyKeyFilePushButton); + initSignatureTypeCombobox(OPTION("httpproxy","signaturetype",[]{return "7";}), ui->comboBox_httpPorxySignatureType); + initStringBox( OPTION("httpproxy","inbound.length",[]{return "3";}), ui->httpProxyInboundTunnelsLenLineEdit); + initStringBox( OPTION("httpproxy","inbound.quantity",[]{return "5";}), ui->httpProxyInboundTunnQuantityLineEdit); + initStringBox( OPTION("httpproxy","outbound.length",[]{return "3";}), ui->httpProxyOutBoundTunnLenLineEdit); + initStringBox( OPTION("httpproxy","outbound.quantity",[]{return "5";}), ui->httpProxyOutboundTunnQuantityLineEdit); + + initCheckBox( OPTION("socksproxy","enabled",[]{return "";}), ui->socksProxyEnabledCheckBox); + initIPAddressBox( OPTION("socksproxy","address",[]{return "";}), ui->socksProxyAddressLineEdit, tr("Socks proxy -> IP address")); + initTCPPortBox( OPTION("socksproxy","port",[]{return "4447";}), ui->socksProxyPortLineEdit, tr("Socks proxy -> Port")); + initFileChooser( OPTION("socksproxy","keys",[]{return "";}), ui->socksProxyKeyFileLineEdit, ui->socksProxyKeyFilePushButton); + initSignatureTypeCombobox(OPTION("socksproxy","signaturetype",[]{return "7";}), ui->comboBox_socksProxySignatureType); + initStringBox( OPTION("socksproxy","inbound.length",[]{return "";}), ui->socksProxyInboundTunnelsLenLineEdit); + initStringBox( OPTION("socksproxy","inbound.quantity",[]{return "";}), ui->socksProxyInboundTunnQuantityLineEdit); + initStringBox( OPTION("socksproxy","outbound.length",[]{return "";}), ui->socksProxyOutBoundTunnLenLineEdit); + initStringBox( OPTION("socksproxy","outbound.quantity",[]{return "";}), ui->socksProxyOutboundTunnQuantityLineEdit); + initIPAddressBox( OPTION("socksproxy","outproxy",[]{return "";}), ui->outproxyAddressLineEdit, tr("Socks proxy -> Outproxy address")); + initTCPPortBox( OPTION("socksproxy","outproxyport",[]{return "";}), ui->outproxyPortLineEdit, tr("Socks proxy -> Outproxy port")); + + initCheckBox( OPTION("sam","enabled",[]{return "false";}), ui->samEnabledCheckBox); + initIPAddressBox( OPTION("sam","address",[]{return "";}), ui->samAddressLineEdit, tr("SAM -> IP address")); + initTCPPortBox( OPTION("sam","port",[]{return "7656";}), ui->samPortLineEdit, tr("SAM -> Port")); + + initCheckBox( OPTION("bob","enabled",[]{return "false";}), ui->bobEnabledCheckBox); + initIPAddressBox( OPTION("bob","address",[]{return "";}), ui->bobAddressLineEdit, tr("BOB -> IP address")); + initTCPPortBox( OPTION("bob","port",[]{return "2827";}), ui->bobPortLineEdit, tr("BOB -> Port")); + + initCheckBox( OPTION("i2cp","enabled",[]{return "false";}), ui->i2cpEnabledCheckBox); + initIPAddressBox( OPTION("i2cp","address",[]{return "";}), ui->i2cpAddressLineEdit, tr("I2CP -> IP address")); + initTCPPortBox( OPTION("i2cp","port",[]{return "7654";}), ui->i2cpPortLineEdit, tr("I2CP -> Port")); + + initCheckBox( OPTION("i2pcontrol","enabled",[]{return "false";}), ui->i2pControlEnabledCheckBox); + initIPAddressBox( OPTION("i2pcontrol","address",[]{return "";}), ui->i2pControlAddressLineEdit, tr("I2PControl -> IP address")); + initTCPPortBox( OPTION("i2pcontrol","port",[]{return "7650";}), ui->i2pControlPortLineEdit, tr("I2PControl -> Port")); + initStringBox( OPTION("i2pcontrol","password",[]{return "";}), ui->i2pControlPasswordLineEdit); + initFileChooser( OPTION("i2pcontrol","cert",[]{return "i2pcontrol.crt.pem";}), ui->i2pControlCertFileLineEdit, ui->i2pControlCertFileBrowsePushButton); + initFileChooser( OPTION("i2pcontrol","key",[]{return "i2pcontrol.key.pem";}), ui->i2pControlKeyFileLineEdit, ui->i2pControlKeyFileBrowsePushButton); + + initCheckBox( OPTION("upnp","enabled",[]{return "true";}), ui->enableUPnPCheckBox); + initStringBox( OPTION("upnp","name",[]{return "I2Pd";}), ui->upnpNameLineEdit); + + initCheckBox( OPTION("precomputation","elgamal",[]{return "false";}), ui->useElGamalPrecomputedTablesCheckBox); + + initCheckBox( OPTION("reseed","verify",[]{return "";}), ui->reseedVerifyCheckBox); + initFileChooser( OPTION("reseed","file",[]{return "";}), ui->reseedFileLineEdit, ui->reseedFileBrowsePushButton); + initStringBox( OPTION("reseed","urls",[]{return "";}), ui->reseedURLsLineEdit); + + initStringBox( OPTION("addressbook","defaulturl",[]{return "";}), ui->addressbookDefaultURLLineEdit); + initStringBox( OPTION("addressbook","subscriptions",[]{return "";}), ui->addressbookSubscriptionsURLslineEdit); + + initUInt16Box( OPTION("limits","transittunnels",[]{return "2500";}), ui->maxNumOfTransitTunnelsLineEdit, tr("maxNumberOfTransitTunnels")); + initUInt16Box( OPTION("limits","openfiles",[]{return "0";}), ui->maxNumOfOpenFilesLineEdit, tr("maxNumberOfOpenFiles")); + initUInt32Box( OPTION("limits","coresize",[]{return "0";}), ui->coreFileMaxSizeNumberLineEdit, tr("coreFileMaxSize")); + + initCheckBox( OPTION("trust","enabled",[]{return "false";}), ui->checkBoxTrustEnable); + initStringBox( OPTION("trust","family",[]{return "";}), ui->lineEditTrustFamily); + initStringBox( OPTION("trust","routers",[]{return "";}), ui->lineEditTrustRouters); + initCheckBox( OPTION("trust","hidden",[]{return "false";}), ui->checkBoxTrustHidden); + + initCheckBox( OPTION("websockets","enabled",[]{return "false";}), ui->checkBoxWebsocketsEnable); + initIPAddressBox( OPTION("websockets","address",[]{return "127.0.0.1";}), ui->lineEdit_webSock_addr, tr("Websocket server -> IP address")); + initTCPPortBox( OPTION("websockets","port",[]{return "7666";}), ui->lineEdit_webSock_port, tr("Websocket server -> Port")); + +# undef OPTION + + loadAllConfigs(); + + //tunnelsFormGridLayoutWidget = new QWidget(ui->tunnelsScrollAreaWidgetContents); + //tunnelsFormGridLayoutWidget->setObjectName(QStringLiteral("tunnelsFormGridLayoutWidget")); + //tunnelsFormGridLayoutWidget->setGeometry(QRect(0, 0, 621, 451)); + ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, 451)); + + appendTunnelForms(""); + + ui->configFileLineEdit->setEnabled(false); + ui->configFileBrowsePushButton->setEnabled(false); + ui->configFileLineEdit->setText(confpath); + ui->tunnelsConfigFileLineEdit->setText(tunconfpath); + + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + item->installListeners(this); + } + + QObject::connect(ui->tunnelsConfigFileLineEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(reloadTunnelsConfigAndUI())); + + QObject::connect(ui->addServerTunnelPushButton, SIGNAL(released()), this, SLOT(addServerTunnelPushButtonReleased())); + QObject::connect(ui->addClientTunnelPushButton, SIGNAL(released()), this, SLOT(addClientTunnelPushButtonReleased())); + #ifndef ANDROID QObject::connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), @@ -70,6 +221,36 @@ MainWindow::MainWindow(QWidget *parent) : //QMetaObject::connectSlotsByName(this); } +void MainWindow::showStatusPage(){ui->stackedWidget->setCurrentIndex(0);} +void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(1);} +void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(2);} +void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(3);} +void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(4);} + +//TODO +void MainWindow::resizeEvent(QResizeEvent *event) +{ + QMainWindow::resizeEvent(event); + onResize(); +} + +//TODO +void MainWindow::onResize() +{ + if(isVisible()){ + ui->horizontalLayoutWidget->resize(ui->horizontalLayoutWidget->width(), height()); + + //status + ui->statusPage->resize(ui->statusPage->width(), height()); + + //tunnels + ui->tunnelsPage->resize(ui->tunnelsPage->width(), height()); + ui->verticalLayoutWidget_6->resize(ui->verticalLayoutWidget_6->width(), height()-20); + /*ui->tunnelsScrollArea->resize(ui->tunnelsScrollArea->width(), + ui->verticalLayoutWidget_6->height()-ui->label_5->height());*/ + } +} + #ifndef ANDROID void MainWindow::createActions() { toggleWindowVisibleAction = new QAction(tr("&Toggle the window"), this); @@ -138,12 +319,13 @@ void MainWindow::handleQuitButton() { void MainWindow::handleGracefulQuitButton() { qDebug("Graceful Quit pressed."); - gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful quit is in progress", 0)); - gracefulQuitButton->setEnabled(false); - gracefulQuitButton->adjustSize(); - verticalLayoutWidget->adjustSize(); + ui->gracefulQuitPushButton->setText(QApplication::translate("MainWindow", "Graceful quit is in progress", 0)); + ui->gracefulQuitPushButton->setEnabled(false); + ui->gracefulQuitPushButton->adjustSize(); + ui->quitPage->adjustSize(); i2p::context.SetAcceptsTunnels (false); // stop accpting tunnels - QTimer::singleShot(10*60*1000/*millis*/, this, SLOT(handleGracefulQuitTimerEvent())); + QTimer::singleShot(10*60*1000//millis + , this, SLOT(handleGracefulQuitTimerEvent())); } void MainWindow::handleGracefulQuitTimerEvent() { @@ -159,7 +341,278 @@ void MainWindow::handleGracefulQuitTimerEvent() { MainWindow::~MainWindow() { qDebug("Destroying main window"); + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + item->deleteLater(); + } + configItems.clear(); //QMessageBox::information(0, "Debug", "mw destructor 1"); //delete ui; //QMessageBox::information(0, "Debug", "mw destructor 2"); } + +FileChooserItem* MainWindow::initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton){ + FileChooserItem* retVal; + retVal=new FileChooserItem(option, fileNameLineEdit, fileBrowsePushButton); + MainWindowItem* super=retVal; + configItems.append(super); + return retVal; +} +void MainWindow::initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton){ + configItems.append(new FolderChooserItem(option, folderLineEdit, folderBrowsePushButton)); +} +/*void MainWindow::initCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new ComboBoxItem(option, comboBox)); + QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(saveAllConfigs())); +}*/ +void MainWindow::initLogLevelCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new LogLevelComboBoxItem(option, comboBox)); +} +void MainWindow::initSignatureTypeCombobox(ConfigOption option, QComboBox* comboBox){ + configItems.append(new SignatureTypeComboBoxItem(option, comboBox)); +} +void MainWindow::initIPAddressBox(ConfigOption option, QLineEdit* addressLineEdit, QString fieldNameTranslated){ + configItems.append(new IPAddressStringItem(option, addressLineEdit, fieldNameTranslated)); +} +void MainWindow::initTCPPortBox(ConfigOption option, QLineEdit* portLineEdit, QString fieldNameTranslated){ + configItems.append(new TCPPortStringItem(option, portLineEdit, fieldNameTranslated)); +} +void MainWindow::initCheckBox(ConfigOption option, QCheckBox* checkBox) { + configItems.append(new CheckBoxItem(option, checkBox)); +} +void MainWindow::initIntegerBox(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ + configItems.append(new IntegerStringItem(option, numberLineEdit, fieldNameTranslated)); +} +void MainWindow::initUInt32Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ + configItems.append(new UInt32StringItem(option, numberLineEdit, fieldNameTranslated)); +} +void MainWindow::initUInt16Box(ConfigOption option, QLineEdit* numberLineEdit, QString fieldNameTranslated){ + configItems.append(new UInt16StringItem(option, numberLineEdit, fieldNameTranslated)); +} +void MainWindow::initStringBox(ConfigOption option, QLineEdit* lineEdit){ + configItems.append(new BaseStringItem(option, lineEdit)); +} +NonGUIOptionItem* MainWindow::initNonGUIOption(ConfigOption option) { + NonGUIOptionItem * retValue; + configItems.append(retValue=new NonGUIOptionItem(option)); + return retValue; +} + +void MainWindow::loadAllConfigs(){ + + //BORROWED FROM ??? //TODO move this code into single location + std::string config; i2p::config::GetOption("conf", config); + std::string datadir; i2p::config::GetOption("datadir", datadir); + bool service = false; +#ifndef _WIN32 + i2p::config::GetOption("service", service); +#endif + i2p::fs::DetectDataDir(datadir, service); + i2p::fs::Init(); + + datadir = i2p::fs::GetDataDir(); + // TODO: drop old name detection in v2.8.0 + if (config == "") + { + config = i2p::fs::DataDirPath("i2p.conf"); + if (i2p::fs::Exists (config)) { + LogPrint(eLogWarning, "Daemon: please rename i2p.conf to i2pd.conf here: ", config); + } else { + config = i2p::fs::DataDirPath("i2pd.conf"); + if (!i2p::fs::Exists (config)) { + // use i2pd.conf only if exists + config = ""; /* reset */ + } + } + } + + //BORROWED FROM ClientContext.cpp //TODO move this code into single location + std::string tunConf; i2p::config::GetOption("tunconf", tunConf); + 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"); + } + } + + this->confpath = config.c_str(); + this->datadir = datadir.c_str(); + this->tunconfpath = tunConf.c_str(); + + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + item->loadFromConfigOption(); + } + + ReadTunnelsConfig(); +} +/** returns false iff not valid items present and save was aborted */ +bool MainWindow::saveAllConfigs(){ + programOptionsWriterCurrentSection=""; + if(!logFileNameOption->lineEdit->text().trimmed().isEmpty())logOption->optionValue=boost::any(std::string("file")); + else logOption->optionValue=boost::any(std::string("stdout")); + daemonOption->optionValue=boost::any(false); + serviceOption->optionValue=boost::any(false); + + std::stringstream out; + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + if(!item->isValid()) return false; + } + + for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { + MainWindowItem* item = *it; + item->saveToStringStream(out); + } + + using namespace std; + + QString backup=confpath+"~"; + if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors + QFile::rename(confpath, backup);//TODO handle errors + ofstream outfile; + outfile.open(confpath.toStdString());//TODO handle errors + outfile << out.str().c_str(); + outfile.close(); + + SaveTunnelsConfig(); + + return true; +} + +void FileChooserItem::pushButtonReleased() { + QString fileName = lineEdit->text().trimmed(); + fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), fileName, tr("All Files (*.*)")); + if(fileName.length()>0)lineEdit->setText(fileName); +} +void FolderChooserItem::pushButtonReleased() { + QString fileName = lineEdit->text().trimmed(); + fileName = QFileDialog::getExistingDirectory(nullptr, tr("Open Folder"), fileName); + if(fileName.length()>0)lineEdit->setText(fileName); +} + +void BaseStringItem::installListeners(MainWindow *mainWindow) { + QObject::connect(lineEdit, SIGNAL(textChanged(const QString &)), mainWindow, SLOT(saveAllConfigs())); +} +void ComboBoxItem::installListeners(MainWindow *mainWindow) { + QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), mainWindow, SLOT(saveAllConfigs())); +} +void CheckBoxItem::installListeners(MainWindow *mainWindow) { + QObject::connect(checkBox, SIGNAL(stateChanged(int)), mainWindow, SLOT(saveAllConfigs())); +} + + +void MainWindowItem::installListeners(MainWindow *mainWindow) {} + +void MainWindow::appendTunnelForms(std::string tunnelNameToFocus) { + int height=0; + ui->tunnelsScrollAreaWidgetContents->setGeometry(0,0,0,0); + for(std::map::iterator it = tunnelConfigs.begin(); it != tunnelConfigs.end(); ++it) { + const std::string& name=it->first; + TunnelConfig* tunconf = it->second; + ServerTunnelConfig* stc = tunconf->asServerTunnelConfig(); + if(stc){ + ServerTunnelPane * tunnelPane=new ServerTunnelPane(&tunnelsPageUpdateListener, stc); + int h=tunnelPane->appendServerTunnelForm(stc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); + height+=h; + qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + tunnelPanes.push_back(tunnelPane); + if(name==tunnelNameToFocus)tunnelPane->getNameLineEdit()->setFocus(); + continue; + } + ClientTunnelConfig* ctc = tunconf->asClientTunnelConfig(); + if(ctc){ + ClientTunnelPane * tunnelPane=new ClientTunnelPane(&tunnelsPageUpdateListener, ctc); + int h=tunnelPane->appendClientTunnelForm(ctc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); + height+=h; + qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + tunnelPanes.push_back(tunnelPane); + if(name==tunnelNameToFocus)tunnelPane->getNameLineEdit()->setFocus(); + continue; + } + throw "unknown TunnelConfig subtype"; + } + qDebug() << "tun.setting height:" << height; + ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, height)); + QList childWidgets = ui->tunnelsScrollAreaWidgetContents->findChildren(); + foreach(QWidget* widget, childWidgets) + widget->show(); +} +void MainWindow::deleteTunnelForms() { + for(std::list::iterator it = tunnelPanes.begin(); it != tunnelPanes.end(); ++it) { + TunnelPane* tp = *it; + ServerTunnelPane* stp = tp->asServerTunnelPane(); + if(stp){ + stp->deleteServerTunnelForm(); + delete stp; + continue; + } + ClientTunnelPane* ctp = tp->asClientTunnelPane(); + if(ctp){ + ctp->deleteClientTunnelForm(); + delete ctp; + continue; + } + throw "unknown TunnelPane subtype"; + } + tunnelPanes.clear(); +} + +void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus) { + deleteTunnelForms(); + for (std::map::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) { + TunnelConfig* tunconf = it->second; + delete tunconf; + } + tunnelConfigs.clear(); + ReadTunnelsConfig(); + appendTunnelForms(tunnelNameToFocus); +} + +void MainWindow::SaveTunnelsConfig() { + std::stringstream out; + + for (std::map::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) { + const std::string& name = it->first; + TunnelConfig* tunconf = it->second; + tunconf->saveHeaderToStringStream(out); + tunconf->saveToStringStream(out); + tunconf->saveI2CPParametersToStringStream(out); + } + + using namespace std; + + QString backup=tunconfpath+"~"; + if(QFile::exists(backup)) QFile::remove(backup);//TODO handle errors + QFile::rename(tunconfpath, backup);//TODO handle errors + ofstream outfile; + outfile.open(tunconfpath.toStdString());//TODO handle errors + outfile << out.str().c_str(); + outfile.close(); + +} + +void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::updated(std::string oldName, TunnelConfig* tunConf) { + if(oldName!=tunConf->getName()) { + //name has changed + std::map::const_iterator it=mainWindow->tunnelConfigs.find(oldName); + if(it!=mainWindow->tunnelConfigs.end())mainWindow->tunnelConfigs.erase(it); + mainWindow->tunnelConfigs[tunConf->getName()]=tunConf; + } + mainWindow->SaveTunnelsConfig(); +} + +void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::needsDeleting(std::string oldName){ + mainWindow->DeleteTunnelNamed(oldName); +} + +void MainWindow::addServerTunnelPushButtonReleased() { + CreateDefaultServerTunnel(); +} + +void MainWindow::addClientTunnelPushButtonReleased() { + CreateDefaultClientTunnel(); +} diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 349eadec..03057f2e 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -1,6 +1,7 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include #include #include #include @@ -9,27 +10,316 @@ #include #include #include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QVBoxLayout" + #ifndef ANDROID -#include -#include -#include +# include +# include +# include #endif +#include + +#include + +#include "MainWindowItems.h" +#include "TunnelPane.h" +#include "ServerTunnelPane.h" +#include "ClientTunnelPane.h" +#include "TunnelConfig.h" + +#include "Config.h" +#include "FS.h" + +#include + +#include +#include + +#include "TunnelsPageUpdateListener.h" + +template +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 + ConfigOption option; +public: + MainWindowItem(ConfigOption option_) : option(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(programOption).value(); + } + virtual void saveToStringStream(std::stringstream& out){ + if(isType(optionValue)) { + std::string v = boost::any_cast(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(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << (boost::any_cast(optionValue) ? "true" : "false"); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else if(isType(optionValue)) { + out << boost::any_cast(optionValue); + }else out << boost::any_cast(optionValue); //let it throw + out << "\n\n"; + } + virtual bool isValid(){return true;} +}; +class NonGUIOptionItem : public MainWindowItem { +public: + NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_) {}; + virtual ~NonGUIOptionItem(){} + virtual bool isValid() { return true; } +}; +class BaseStringItem : public MainWindowItem { + Q_OBJECT +public: + QLineEdit* lineEdit; + BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_) : MainWindowItem(option_), lineEdit(lineEdit_){}; + virtual ~BaseStringItem(){} + virtual void installListeners(MainWindow *mainWindow); + virtual QString toString(){ + return boost::any_cast(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() { return true; } +}; +class FileOrFolderChooserItem : public BaseStringItem { +public: + QPushButton* browsePushButton; + FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_) : + BaseStringItem(option_, lineEdit_), browsePushButton(browsePushButton_) {} + virtual ~FileOrFolderChooserItem(){} +}; +class FileChooserItem : public FileOrFolderChooserItem { + Q_OBJECT +private slots: + void pushButtonReleased(); +public: + FileChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_) { + 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_) : + FileOrFolderChooserItem(option_, lineEdit_, browsePushButton_) { + QObject::connect(browsePushButton, SIGNAL(released()), this, SLOT(pushButtonReleased())); + } +}; +class ComboBoxItem : public MainWindowItem { +public: + QComboBox* comboBox; + ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_), comboBox(comboBox_){}; + virtual ~ComboBoxItem(){} + virtual void installListeners(MainWindow *mainWindow); + virtual void loadFromConfigOption()=0; + virtual void saveToStringStream(std::stringstream& out)=0; + virtual bool isValid() { return true; } +}; +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(optionValue).c_str(); + comboBox->setCurrentText(QString(ll)); + } + virtual void saveToStringStream(std::stringstream& out){ + optionValue=comboBox->currentText().toStdString(); + MainWindowItem::saveToStringStream(out); + } + virtual bool isValid() { return true; } +}; +class SignatureTypeComboBoxItem : public ComboBoxItem { +public: + SignatureTypeComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}; + virtual ~SignatureTypeComboBoxItem(){} + virtual void loadFromConfigOption(){//TODO + MainWindowItem::loadFromConfigOption(); + comboBox->setCurrentText(QString::number(boost::any_cast(optionValue))); + } + virtual void saveToStringStream(std::stringstream& out){//TODO + QString txt = comboBox->currentText(); + if(txt.isEmpty()) + optionValue=std::string(); + else + optionValue=(unsigned short)std::stoi(txt.toStdString()); + MainWindowItem::saveToStringStream(out); + } + virtual bool isValid() { return true; } +}; +class CheckBoxItem : public MainWindowItem { +public: + QCheckBox* checkBox; + CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_), checkBox(checkBox_){}; + virtual ~CheckBoxItem(){} + virtual void installListeners(MainWindow *mainWindow); + virtual void loadFromConfigOption(){ + MainWindowItem::loadFromConfigOption(); + checkBox->setChecked(boost::any_cast(optionValue)); + } + virtual void saveToStringStream(std::stringstream& out){ + optionValue=checkBox->isChecked(); + MainWindowItem::saveToStringStream(out); + } + virtual bool isValid() { return true; } +}; +class BaseFormattedStringItem : public BaseStringItem { +public: + QString fieldNameTranslated; + BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : + BaseStringItem(option_, lineEdit_), fieldNameTranslated(fieldNameTranslated_) {}; + virtual ~BaseFormattedStringItem(){} + virtual bool isValid()=0; +}; +class IntegerStringItem : public BaseFormattedStringItem { +public: + IntegerStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + virtual ~IntegerStringItem(){} + virtual bool isValid(){return true;} + virtual QString toString(){return QString::number(boost::any_cast(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_) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + virtual ~UShortStringItem(){} + virtual bool isValid(){return true;} + virtual QString toString(){return QString::number(boost::any_cast(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_) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + virtual ~UInt32StringItem(){} + virtual bool isValid(){return true;} + virtual QString toString(){return QString::number(boost::any_cast(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_) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + virtual ~UInt16StringItem(){} + virtual bool isValid(){return true;} + virtual QString toString(){return QString::number(boost::any_cast(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_) : + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + virtual bool isValid(){return true;} +}; +class TCPPortStringItem : public UShortStringItem { +public: + TCPPortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : + UShortStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + virtual bool isValid(){return true;} +}; + namespace Ui { class MainWindow; } -class MainWindow : public QMainWindow -{ +using namespace i2p::client; + +class TunnelPane; + +class MainWindow : public QMainWindow { Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent=0); ~MainWindow(); + //typedef std::function DefaultValueGetter; + //#ifndef ANDROID // void setVisible(bool visible); //#endif @@ -43,30 +333,343 @@ private slots: void iconActivated(QSystemTrayIcon::ActivationReason reason); void toggleVisibilitySlot(); #endif + void showStatusPage(); + void showSettingsPage(); + void showTunnelsPage(); + void showRestartPage(); + void showQuitPage(); private: #ifndef ANDROID void createActions(); void createTrayIcon(); -#endif - - QWidget *centralWidget; - QWidget *verticalLayoutWidget; - QVBoxLayout *verticalLayout1; - QPushButton *quitButton; - QPushButton *gracefulQuitButton; - -#ifndef ANDROID bool quitting; QAction *toggleWindowVisibleAction; QSystemTrayIcon *trayIcon; QMenu *trayIconMenu; #endif + Ui::MainWindow* ui; + protected: #ifndef ANDROID void closeEvent(QCloseEvent *event); #endif + void resizeEvent(QResizeEvent* event); + void onResize(); + + QList configItems; + NonGUIOptionItem* logOption; + NonGUIOptionItem* daemonOption; + NonGUIOptionItem* serviceOption; + FileChooserItem* logFileNameOption; + + FileChooserItem* initFileChooser(ConfigOption option, QLineEdit* fileNameLineEdit, QPushButton* fileBrowsePushButton); + void initFolderChooser(ConfigOption option, QLineEdit* folderLineEdit, QPushButton* folderBrowsePushButton); + //void initCombobox(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(); + +public slots: + /** returns false iff not valid items present and save was aborted */ + bool saveAllConfigs(); + void SaveTunnelsConfig(); + void reloadTunnelsConfigAndUI(std::string tunnelNameToFocus); + + //focus none + void reloadTunnelsConfigAndUI() { reloadTunnelsConfigAndUI(""); } + void addServerTunnelPushButtonReleased(); + void addClientTunnelPushButtonReleased(); + +private: + QString datadir; + QString confpath; + QString tunconfpath; + + std::map tunnelConfigs; + std::list tunnelPanes; + + void appendTunnelForms(std::string tunnelNameToFocus); + void deleteTunnelForms(); + + + /* + + TODO signaturetype + + */ + + template + 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 + void ReadI2CPOptions (const Section& section, std::map& 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())); + 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)); + } + + + void DeleteTunnelNamed(std::string name) { + std::map::const_iterator it=tunnelConfigs.find(name); + if(it!=tunnelConfigs.end()){ + TunnelConfig* tc=it->second; + tunnelConfigs.erase(it); + delete tc; + SaveTunnelsConfig(); + reloadTunnelsConfigAndUI(""); + } + } + + 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; + 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); + + SaveTunnelsConfig(); + reloadTunnelsConfigAndUI(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; + uint32_t maxConns = i2p::stream::DEFAULT_MAX_CONNS_PER_MIN; + std::string address = "127.0.0.1"; + bool isUniqueLocal = true; + + // I2CP + I2CPParameters i2cpParameters; + CreateDefaultI2CPOptions (i2cpParameters); + + tunnelConfigs[name]=new ServerTunnelConfig(name, QString(type.c_str()), i2cpParameters, + host, + port, + keys, + inPort, + accessList, + hostOverride, + webircpass, + gzip, + sigType, + maxConns, + address, + isUniqueLocal); + + + SaveTunnelsConfig(); + reloadTunnelsConfigAndUI(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 (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 (I2P_CLIENT_TUNNEL_DESTINATION); + int port = section.second.get (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 destinationPort = section.second.get (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 options; + I2CPParameters i2cpParameters; + ReadI2CPOptions (section, options, i2cpParameters); + + tunnelConfigs[name]=new ClientTunnelConfig(name, QString(type.c_str()), i2cpParameters, + dest, + port, + keys, + address, + destinationPort, + sigType); + } + 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 (I2P_SERVER_TUNNEL_HOST); + int port = section.second.get (I2P_SERVER_TUNNEL_PORT); + std::string keys = section.second.get (I2P_SERVER_TUNNEL_KEYS); + // optional params + 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 (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); + uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); + bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); + + // I2CP + std::map options; + I2CPParameters i2cpParameters; + ReadI2CPOptions (section, options, i2cpParameters); + + /* + std::set 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, + maxConns, + address, + isUniqueLocal); + } + 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; }; #endif // MAINWINDOW_H diff --git a/qt/i2pd_qt/mainwindow.ui b/qt/i2pd_qt/mainwindow.ui index d73e7743..ca07c036 100644 --- a/qt/i2pd_qt/mainwindow.ui +++ b/qt/i2pd_qt/mainwindow.ui @@ -6,42 +6,3185 @@ 0 0 - 800 - 480 + 816 + 5000 MainWindow - + + + 0 + 0 + + + + + 0 + 516 + + + + + 16777215 + 516 + + + 10 - 20 - 771 - 441 + 10 + 801 + 518 - + + + QLayout::SetDefaultConstraint + - + + + QLayout::SetMinimumSize + + + + + true + + + Status + + + + + + + true + + + Settings + + + + + + + true + + + Tunnels + + + + + + + true + + + Restart + + + + + + + true + + + Quit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + - + 0 0 - - Quit + + + 0 + 516 + - - - - - - Graceful Quit + + + 16777215 + 516 + + + 1 + + + + + + 0 + 0 + 671 + 5000 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Status + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 0 + + + + + + 0 + 0 + 701 + 400 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Settings + + + + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + + + 0 + 0 + 679 + 400 + + + + + 0 + 0 + + + + + + 10 + 11 + 679 + 2962 + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + SAM interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Windows-specific options + + + + + + + + 0 + 44 + + + + + 16777215 + 44 + + + + Cryptography + + + + + 0 + 20 + 661 + 22 + + + + Use ElGamal precomputed tables + + + + + + + + + 0 + 107 + + + + + 16777215 + 107 + + + + Logging + + + Qt::AlignJustify|Qt::AlignTop + + + + + -1 + 19 + 661 + 91 + + + + + QLayout::SetMinimumSize + + + + + QLayout::SetMaximumSize + + + + + Log file: + + + + + + + + + + Browse… + + + + + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + Log level: + + + + + + + + Error + + + + + Warn + + + + + Info + + + + + Debug + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 68 + + + + + 16777215 + 68 + + + + UPnP + + + + + 0 + 20 + 97 + 22 + + + + Enable + + + + + + 0 + 40 + 661 + 31 + + + + + + + Name i2pd appears in UPnP forwardings list: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + I2CP interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 48 + + + + + 16777215 + 48 + + + + Tunnels configuration file: + + + + + 0 + 20 + 661 + 31 + + + + + QLayout::SetMaximumSize + + + + + + + + Browse… + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + BOB interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + General options + + + + + + + + 0 + 0 + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + Router external address (for incoming connections) + + + Qt::AlignJustify|Qt::AlignTop + + + + + 0 + 20 + 661 + 81 + + + + + QLayout::SetMinAndMaxSize + + + + + QLayout::SetMinAndMaxSize + + + + + Host: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetMinAndMaxSize + + + + + Port (leave empty to auto-assign): + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 78 + + + + + 16777215 + 78 + + + + Addressbook settings + + + + + 0 + 20 + 661 + 31 + + + + + + + Addressbook default subscription URL for initial setup: + + + + + + + + + + + + 0 + 50 + 661 + 31 + + + + + + + Addressbook subscriptions URLs, separated by comma: + + + + + + + + + + + + + + + 0 + 280 + + + + + 16777215 + 280 + + + + HTTP proxy + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Keys file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Inbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 190 + 661 + 31 + + + + + + + Inbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 220 + 661 + 31 + + + + + + + Outbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 250 + 661 + 31 + + + + + + + Outbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Signature type: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Various options + + + + + + + + 0 + 48 + + + + + 16777215 + 48 + + + + Data folder (for storage of i2pd data — RI, keys, peer profiles, …): + + + + + 0 + 20 + 661 + 31 + + + + + QLayout::SetMaximumSize + + + + + + + + Browse… + + + + + + + + + + + + 0 + 0 + + + + + 0 + 215 + + + + + 16777215 + 215 + + + + Router options + + + + + 0 + 20 + 661 + 188 + + + + + + + Enable communication through ipv6 + + + + + + + Router will not accept transit tunnels at startup + + + + + + + Router will be floodfill + + + + + + + + + Bandwidth limit (integer): + + + + + + + + + + KBps + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Family (name of a family router belongs to): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QLayout::SetMaximumSize + + + + + NetID (network ID router belongs to. The main I2P ID is 2): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + 108 + + + + + 16777215 + 108 + + + + Limits + + + + + 0 + 20 + 661 + 31 + + + + + + + Maximum number of transit tunnels: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 50 + 661 + 31 + + + + + + + Maximum number of open files (0 — use system limit): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 80 + 661 + 31 + + + + + + + Maximum size of core file in Kb (0 — use system limit): + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 48 + + + + + 16777215 + 48 + + + + Pid file: + + + + + 0 + 20 + 661 + 31 + + + + + + + + + + Browse… + + + + + + + + + + + + 0 + 98 + + + + + 16777215 + 98 + + + + Reseeding + + + + + 0 + 20 + 661 + 22 + + + + Request SU3 signature verification + + + + + + 0 + 40 + 661 + 31 + + + + + + + SU3 file to reseed from: + + + + + + + + + + Browse… + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Reseed URLs, separated by comma: + + + + + + + + + + + + + + + 0 + 180 + + + + + 16777215 + 180 + + + + Trust options + + + + + 0 + 20 + 661 + 21 + + + + Enable explicit trust options + + + + + + 390 + 40 + 271 + 23 + + + + + + + 0 + 40 + 391 + 42 + + + + Make direct I2P connections only to +routers in specified Family: + + + + + + 0 + 82 + 661 + 42 + + + + Make direct I2P connections only to routers specified here. +Comma separated list of base64 identities: + + + + + + 0 + 124 + 661 + 23 + + + + + + + 0 + 147 + 661 + 21 + + + + Should we hide our router from other routers? + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 13 + + + + Ports + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Insomnia (prevent system from sleeping) + + + + + + + + 0 + 189 + + + + + 16777215 + 189 + + + + I2PControl interface + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + Certificate file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Key file: + + + + + + + + + + Browse… + + + + + + + + + + + + 0 + 0 + + + + + 0 + 46 + + + + + 16777215 + 46 + + + + Configuration file: + + + + + 0 + 18 + 661 + 31 + + + + + QLayout::SetMinimumSize + + + + + + + + Browse… + + + + + + + + + + + + 0 + 110 + + + + + 16777215 + 110 + + + + Websockets server + + + + + 0 + 20 + 85 + 21 + + + + Enable + + + + + + 0 + 40 + 661 + 31 + + + + + + + Address to bind websocket server on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to bind websocket server on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 179 + + + + + 16777215 + 179 + + + + HTTP webconsole + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 321 + 22 + + + + Enable basic HTTP auth + + + + + + 60 + 120 + 601 + 31 + + + + + + + Username: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 60 + 150 + 601 + 31 + + + + + + + Password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 370 + + + + + 16777215 + 370 + + + + Socks proxy + + + + + 0 + 20 + 97 + 22 + + + + Enabled + + + + + + 0 + 40 + 661 + 31 + + + + + + + IP address to listen on: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 70 + 661 + 31 + + + + + + + Port to listen on: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 100 + 661 + 31 + + + + + + + Keys file: + + + + + + + + + + Browse… + + + + + + + + + 0 + 160 + 661 + 31 + + + + + + + Inbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 190 + 661 + 31 + + + + + + + Inbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 220 + 661 + 31 + + + + + + + Outbound tunnels length: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 250 + 661 + 31 + + + + + + + Outbound tunnels quantity: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 280 + 661 + 31 + + + + + + + Outproxy address: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 310 + 661 + 31 + + + + + + + Outproxy port: + + + + + + + + 80 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + 130 + 661 + 31 + + + + + + + SIgnature type: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 681 + 460 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Tunnels + + + + + + + + + Add Client Tunnel + + + + + + + Add Server Tunnel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::ScrollBarAlwaysOn + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 663 + 395 + + + + + + + + + + + + + 0 + 0 + 681 + 451 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Restart + + + + + + + Restart i2pd + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 0 + + + + + + 0 + 0 + 671 + 480 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Quit + + + + + + + Quit Now + + + + + + + Graceful Quit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + @@ -50,40 +3193,7 @@ - - - quitButton - released() - MainWindow - handleQuitButton() - - - 384 - 244 - - - 373 - 419 - - - - - gracefulShutdownButton - released() - MainWindow - handleGracefulQuitButton() - - - 395 - 319 - - - 399 - 239 - - - - + handleQuitButton() handleGracefulQuitButton() diff --git a/qt/i2pd_qt/tunnelform.ui b/qt/i2pd_qt/tunnelform.ui new file mode 100644 index 00000000..61e54770 --- /dev/null +++ b/qt/i2pd_qt/tunnelform.ui @@ -0,0 +1,104 @@ + + + Form + + + + 0 + 0 + 527 + 452 + + + + Form + + + + + 0 + 0 + 521 + 451 + + + + + + + server_tunnel_name + + + + + 0 + 20 + 511 + 421 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete + + + + + + + + + + + Host: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + +