Reactivate openvpn plugin

pull/1/head
Timothy Pearson 12 years ago
parent 3c57e87e07
commit 60bf9a139f

@ -33,8 +33,9 @@ PluginManager* PluginManager::_instance;
PluginManager* PluginManager::getInstance() PluginManager* PluginManager::getInstance()
{ {
if (_instance) if (_instance) {
return _instance; return _instance;
}
return new PluginManager(TQT_TQOBJECT(TDENetworkManager::getInstance()), "pluginmanager"); return new PluginManager(TQT_TQOBJECT(TDENetworkManager::getInstance()), "pluginmanager");
} }
@ -45,22 +46,21 @@ PluginManager::PluginManager(TQObject* parent, const char* name)
this->_plugins = KPluginInfo::fromServices( KTrader::self()->query( TQString::fromLatin1( "TDENetworkManager/Plugin" ))); this->_plugins = KPluginInfo::fromServices( KTrader::self()->query( TQString::fromLatin1( "TDENetworkManager/Plugin" )));
// a bit debug output // a bit debug output
for(TQValueList<KPluginInfo*>::ConstIterator it = _plugins.begin(); it != _plugins.end(); ++it) for(TQValueList<KPluginInfo*>::ConstIterator it = _plugins.begin(); it != _plugins.end(); ++it) {
kdDebug() << k_funcinfo << TQString("Found Plugin '%1'").arg((*it)->pluginName()) << endl; kdDebug() << k_funcinfo << TQString("Found Plugin '%1'").arg((*it)->pluginName()) << endl;
} }
}
PluginManager::~PluginManager() PluginManager::~PluginManager()
{ {
// delete all loaded plugins // delete all loaded plugins
while(!_loadedPlugins.empty()) while(!_loadedPlugins.empty()) {
{
PluginMap::Iterator it = _loadedPlugins.begin(); PluginMap::Iterator it = _loadedPlugins.begin();
_loadedPlugins.remove(it); _loadedPlugins.remove(it);
} }
// delete all available plugininfos // delete all available plugininfos
while(!_plugins.empty()) while(!_plugins.empty()) {
{
TQValueList<KPluginInfo*>::Iterator it = _plugins.begin(); TQValueList<KPluginInfo*>::Iterator it = _plugins.begin();
delete *it; delete *it;
_plugins.remove(it); _plugins.remove(it);
@ -71,24 +71,23 @@ TQStringList PluginManager::getPluginList(const TQString& serviceType, const TQS
{ {
TQStringList ret; TQStringList ret;
// find a suitable plugin // find a suitable plugin
for(TQValueList<KPluginInfo*>::ConstIterator it = _plugins.begin(); it != _plugins.end(); ++it) for(TQValueList<KPluginInfo*>::ConstIterator it = _plugins.begin(); it != _plugins.end(); ++it) {
{ if ((*it)->service()->serviceTypes().contains(serviceType) > 0) {
if ((*it)->service()->serviceTypes().contains(serviceType) > 0) if ((*it)->property(property).toString().contains(value)) {
if ((*it)->property(property).toString().contains(value))
ret.append( (*it)->pluginName() ); ret.append( (*it)->pluginName() );
} }
}
}
return ret; return ret;
} }
Plugin* PluginManager::getPlugin(const TQString& pluginID) Plugin* PluginManager::getPlugin(const TQString& pluginID)
{ {
KPluginInfo* info = infoForPluginID(pluginID); KPluginInfo* info = infoForPluginID(pluginID);
if (_loadedPlugins.contains(info)) if (_loadedPlugins.contains(info)) {
{
return _loadedPlugins[info]; return _loadedPlugins[info];
} }
else else {
{
return loadPlugin(pluginID); return loadPlugin(pluginID);
} }
return NULL; return NULL;
@ -101,8 +100,7 @@ const KPluginInfo* PluginManager::getPluginInfo(const TQString& pluginID)
const KPluginInfo* PluginManager::getPluginInfo(const Plugin* plugin) const KPluginInfo* PluginManager::getPluginInfo(const Plugin* plugin)
{ {
for(PluginMap::ConstIterator it = _loadedPlugins.begin(); it != _loadedPlugins.end(); ++it) for(PluginMap::ConstIterator it = _loadedPlugins.begin(); it != _loadedPlugins.end(); ++it) {
{
if (it.data() == plugin) if (it.data() == plugin)
return it.key(); return it.key();
} }
@ -112,8 +110,7 @@ const KPluginInfo* PluginManager::getPluginInfo(const Plugin* plugin)
void PluginManager::loadAllPlugins() void PluginManager::loadAllPlugins()
{ {
// iterate over all plugins // iterate over all plugins
for(TQValueList<KPluginInfo*>::ConstIterator it = _plugins.begin(); it != _plugins.end(); ++it) for(TQValueList<KPluginInfo*>::ConstIterator it = _plugins.begin(); it != _plugins.end(); ++it) {
{
// load Plugin // load Plugin
loadPlugin((*it)->pluginName()); loadPlugin((*it)->pluginName());
} }
@ -129,13 +126,11 @@ Plugin* PluginManager::loadPlugin(const TQString& pluginID)
TQString::fromLatin1( "[X-TDE-PluginInfo-Name]=='%1'" ).arg( pluginID ), this, 0, TQStringList(), &error ); TQString::fromLatin1( "[X-TDE-PluginInfo-Name]=='%1'" ).arg( pluginID ), this, 0, TQStringList(), &error );
// plugin loaded? // plugin loaded?
if (plugin) if (plugin) {
{
kdDebug() << k_funcinfo << TQString(i18n("successfully loaded plugin '%1'")).arg(info->pluginName()) << endl; kdDebug() << k_funcinfo << TQString(i18n("successfully loaded plugin '%1'")).arg(info->pluginName()) << endl;
_loadedPlugins.insert(info, plugin); _loadedPlugins.insert(info, plugin);
} }
else else {
{
// error // error
switch( error ) switch( error )
{ {
@ -172,11 +167,11 @@ Plugin* PluginManager::loadPlugin(const TQString& pluginID)
KPluginInfo * PluginManager::infoForPluginID( const TQString& pluginID ) const KPluginInfo * PluginManager::infoForPluginID( const TQString& pluginID ) const
{ {
TQValueList<KPluginInfo *>::ConstIterator it; TQValueList<KPluginInfo *>::ConstIterator it;
for ( it = this->_plugins.begin(); it != this->_plugins.end(); ++it ) for ( it = this->_plugins.begin(); it != this->_plugins.end(); ++it ) {
{ if ( ( *it )->pluginName() == pluginID ) {
if ( ( *it )->pluginName() == pluginID )
return *it; return *it;
} }
}
return 0L; return 0L;
} }

@ -54,11 +54,9 @@ VPNService::VPNService(const TQString& serviceName, const TQString& service, TQO
// query if a plugin for this vpn service is available // query if a plugin for this vpn service is available
PluginManager* plugMan = PluginManager::getInstance(); PluginManager* plugMan = PluginManager::getInstance();
if (plugMan) if (plugMan) {
{
TQStringList list = plugMan->getPluginList("TDENetworkManager/VPNPlugin", "X-NetworkManager-Services", serviceName); TQStringList list = plugMan->getPluginList("TDENetworkManager/VPNPlugin", "X-NetworkManager-Services", serviceName);
if (list.size() > 0) if (list.size() > 0) {
{
// get the first VPN Plugin handling our VPNService // get the first VPN Plugin handling our VPNService
VPNPlugin* vpnPlugin = dynamic_cast<VPNPlugin*>( plugMan->getPlugin(list.first()) ); VPNPlugin* vpnPlugin = dynamic_cast<VPNPlugin*>( plugMan->getPlugin(list.first()) );
if (vpnPlugin) if (vpnPlugin)

@ -9,7 +9,7 @@
# #
################################################# #################################################
# add_subdirectory( openvpn ) add_subdirectory( openvpn )
add_subdirectory( pptp ) add_subdirectory( pptp )
# add_subdirectory( strongswan ) # add_subdirectory( strongswan )
add_subdirectory( vpnc ) add_subdirectory( vpnc )

@ -1,2 +1,3 @@
Timothy Pearson <kb9vqf@pearsoncomputing.net>
Helmut Schaa <hschaa@suse.de>, <helmut.schaa@gmx.de> Helmut Schaa <hschaa@suse.de>, <helmut.schaa@gmx.de>
Thomas Kallenberg <tkallenb@hsr.ch> <thomas@no-more-secrets.ch> Thomas Kallenberg <tkallenb@hsr.ch> <thomas@no-more-secrets.ch>

@ -0,0 +1,14 @@
#################################################
#
# (C) 2012 Timothy Pearson
# kb9vqf (AT) pearsoncomputing.net
#
# Improvements and feedback are welcome
#
# This file is released under GPL >= 2
#
#################################################
add_subdirectory( src )
install( FILES tdenetman_openvpn.desktop DESTINATION ${SERVICES_INSTALL_DIR} )

@ -0,0 +1,43 @@
#################################################
#
# (C) 2012 Timothy Pearson
# kb9vqf (AT) pearsoncomputing.net
#
# Improvements and feedback are welcome
#
# This file is released under GPL >= 2
#
#################################################
add_definitions( -UQT_NO_ASCII_CAST )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/tdenetworkmanager/src/settings
${CMAKE_SOURCE_DIR}/tdenetworkmanager/src/configwidgets
${TDE_INCLUDE_DIR}
${TQT_INCLUDE_DIRS}
${DBUS_TQT_INCLUDE_DIRS}
${NM_UTIL_INCLUDE_DIRS}
)
link_directories(
${TQT_LIBRARY_DIRS}
)
##### tdenetman_openvpn (module) ################
set( target tdenetman_openvpn )
set( ${target}_SRCS
tdenetman-openvpn.cpp
openvpnprop.ui
openvpnauth.ui
)
tde_add_kpart( ${target} AUTOMOC
SOURCES ${${target}_SRCS}
LINK tdeinit_kded-shared tdeinit_tdenetworkmanager-shared
DESTINATION ${PLUGIN_INSTALL_DIR}
)

@ -36,12 +36,11 @@
#include <tqwidgetstack.h> #include <tqwidgetstack.h>
#include <tqfileinfo.h> #include <tqfileinfo.h>
#include <tqhostaddress.h> #include <tqhostaddress.h>
#include <tqdbusdata.h>
#include "knetworkmanager-openvpn.h" #include "tdenetman-openvpn.h"
typedef KGenericFactory<OpenVPNPlugin> OpenVPNPluginFactory; typedef KGenericFactory<OpenVPNPlugin> OpenVPNPluginFactory;
K_EXPORT_COMPONENT_FACTORY( knetworkmanager_openvpn, OpenVPNPluginFactory("knetworkmanager_openvpn")); K_EXPORT_COMPONENT_FACTORY( tdenetman_openvpn, OpenVPNPluginFactory("tdenetman_openvpn"));
/************************************ /************************************
* OpenVPNPlugin * OpenVPNPlugin
@ -177,21 +176,23 @@ void OpenVPNConfig::getCipherModes()
{ {
// get all possible cipher modes // get all possible cipher modes
TQString openvpn = findOpenVPNBinary(); TQString openvpn = findOpenVPNBinary();
if (!openvpn.isNull()) if (!openvpn.isNull()) {
{
KProcess* cipherHelper = new KProcess(); KProcess* cipherHelper = new KProcess();
cipherHelper->setUseShell(true, "/bin/sh"); cipherHelper->setUseShell(true, "/bin/sh");
*cipherHelper << TQString::fromLatin1("%1 --show-ciphers | awk '/^[A-Z][A-Z0-9]+-/ { print $1 }'").arg(openvpn); *cipherHelper << TQString::fromLatin1("%1 --show-ciphers | awk '/^[A-Z][A-Z0-9]+-/ { print $1 }'").arg(openvpn);
connect (cipherHelper, TQT_SIGNAL(receivedStdout(KProcess*, char*, int)), this, TQT_SLOT(receiveCipherData(KProcess*, char*, int))); connect (cipherHelper, TQT_SIGNAL(receivedStdout(KProcess*, char*, int)), this, TQT_SLOT(receiveCipherData(KProcess*, char*, int)));
kdDebug() << "starting openvpn to get cipher modes" << endl; kdDebug() << "starting openvpn to get cipher modes" << endl;
if (!cipherHelper->start(KProcess::Block, KProcess::Stdout)) if (!cipherHelper->start(KProcess::Block, KProcess::Stdout)) {
kdDebug() << "error starting openvpn" << endl; kdDebug() << "error starting openvpn" << endl;
} }
}
} }
void OpenVPNConfig::setVPNData(const TQStringList& routes, const TQMap<TQString, TQString>& properties) void OpenVPNConfig::setVPNData(TDENetworkSingleRouteConfigurationList& routes, TDENetworkSettingsMap& properties, TDENetworkSettingsMap& secrets)
{ {
m_vpnProperties = properties;
m_vpnSecrets = secrets;
// fill up our inputfields // fill up our inputfields
for(TQMap<TQString, TQString>::ConstIterator it = properties.begin(); it != properties.end(); ++it) for(TQMap<TQString, TQString>::ConstIterator it = properties.begin(); it != properties.end(); ++it)
{ {
@ -283,63 +284,98 @@ void OpenVPNConfig::setVPNData(const TQStringList& routes, const TQMap<TQString,
if (!routes.empty()) if (!routes.empty())
{ {
_openvpnWidget->chkIPAdresses->setChecked(true); _openvpnWidget->chkIPAdresses->setChecked(true);
_openvpnWidget->routes->setText(routes.join(" ")); TQStringList routesText;
for (TDENetworkSingleRouteConfigurationList::Iterator it = routes.begin(); it != routes.end(); ++it) {
routesText.append(TQString("%1/%2").arg((*it).ipAddress.toString()).arg((*it).networkMask.toCIDRMask()));
}
_openvpnWidget->routes->setText(routesText.join(" "));
} }
} }
TQMap<TQString, TQString>OpenVPNConfig::getVPNProperties() TDENetworkSettingsMap OpenVPNConfig::getVPNProperties()
{ {
// build a StingList of properties // Build a list of properties
TQMap<TQString, TQString> strlist; m_vpnProperties.insert("connection-type", TQString::number(OpenVPNConnectionType::mapConnectionType2String((OpenVPNConnectionType::CONNECTIONTYPE)_openvpnWidget->cboConnectionType->currentItem())));
m_vpnProperties.insert("remote", TQString(_openvpnWidget->gateway->text()));
strlist.insert("connection-type", TQString::number(OpenVPNConnectionType::mapConnectionType2String((OpenVPNConnectionType::CONNECTIONTYPE)_openvpnWidget->cboConnectionType->currentItem())));
strlist.insert("remote", TQString(_openvpnWidget->gateway->text()));
// port is not necessary // port is not necessary
if (!_openvpnWidget->port->text().isEmpty() && !_openvpnWidget->chkDefaultPort->isChecked()) if (!_openvpnWidget->port->text().isEmpty() && !_openvpnWidget->chkDefaultPort->isChecked()) {
strlist.insert("port", _openvpnWidget->port->text()); m_vpnProperties.insert("port", _openvpnWidget->port->text());
}
else {
m_vpnProperties.remove("port");
}
strlist.insert("ca", TQString(_openvpnWidget->editCA->url())); m_vpnProperties.insert("ca", TQString(_openvpnWidget->editCA->url()));
strlist.insert("cert",TQString(_openvpnWidget->editCert->url() )); m_vpnProperties.insert("cert",TQString(_openvpnWidget->editCert->url() ));
strlist.insert("key", TQString(_openvpnWidget->editKey->url())); m_vpnProperties.insert("key", TQString(_openvpnWidget->editKey->url()));
if (_openvpnWidget->chkUseCipher->isChecked()) if (_openvpnWidget->chkUseCipher->isChecked()) {
strlist.insert("cipher", TQString(_openvpnWidget->cboCipher->currentText())); m_vpnProperties.insert("cipher", TQString(_openvpnWidget->cboCipher->currentText()));
}
else {
m_vpnProperties.remove("cipher");
}
if (_openvpnWidget->chkUseLZO->isChecked()) if (_openvpnWidget->chkUseLZO->isChecked()) {
strlist.insert("comp-lzo", TQString("true")); m_vpnProperties.insert("comp-lzo", TQString("true"));
else }
strlist.insert("comp-lzo", TQString("false")); else {
m_vpnProperties.insert("comp-lzo", TQString("false"));
}
strlist.insert("static-key", TQString(_openvpnWidget->editSharedKey->url())); m_vpnProperties.insert("static-key", TQString(_openvpnWidget->editSharedKey->url()));
strlist.insert("username", TQString(_openvpnWidget->editUsername->text())); m_vpnProperties.insert("username", TQString(_openvpnWidget->editUsername->text()));
strlist.insert("local-ip", TQString(_openvpnWidget->editLocalIP->text())); m_vpnProperties.insert("local-ip", TQString(_openvpnWidget->editLocalIP->text()));
strlist.insert("remote-ip", TQString(_openvpnWidget->editRemoteIP->text())); m_vpnProperties.insert("remote-ip", TQString(_openvpnWidget->editRemoteIP->text()));
if (_openvpnWidget->chkUseTAP->isChecked()) { if (_openvpnWidget->chkUseTAP->isChecked()) {
strlist.insert("tap-dev", "true"); m_vpnProperties.insert("tap-dev", "true");
strlist.insert("proto-tcp", "true"); m_vpnProperties.insert("proto-tcp", "true");
} else { }
strlist.insert("tap-dev", "false"); else {
strlist.insert("proto-tcp", "false"); m_vpnProperties.insert("tap-dev", "false");
m_vpnProperties.insert("proto-tcp", "false");
}
if (_openvpnWidget->chkUseTLS->isChecked()) {
m_vpnProperties.insert("ta", TQString(_openvpnWidget->editTLSAuth->url()));
}
else {
m_vpnProperties.remove("ta");
} }
if (_openvpnWidget->chkUseTLS->isChecked()) m_vpnProperties.insert("ta-dir", TQString(_openvpnWidget->cboDirection->currentText()));
strlist.insert("ta", TQString(_openvpnWidget->editTLSAuth->url()));
return m_vpnProperties;
}
strlist.insert("ta-dir", TQString(_openvpnWidget->cboDirection->currentText())); TDENetworkSettingsMap OpenVPNConfig::getVPNSecrets() {
// Build a list of secrets
// FIXME
return strlist; return m_vpnSecrets;
} }
TQStringList OpenVPNConfig::getVPNRoutes() TDENetworkSingleRouteConfigurationList OpenVPNConfig::getVPNRoutes()
{ {
TDENetworkSingleRouteConfigurationList ret;
TQStringList strlist; TQStringList strlist;
if(_openvpnWidget->chkIPAdresses->isChecked()) if(_openvpnWidget->chkIPAdresses->isChecked()) {
{
strlist = TQStringList::split(" ", _openvpnWidget->routes->text()); strlist = TQStringList::split(" ", _openvpnWidget->routes->text());
} }
return strlist;
for (TQStringList::Iterator it = strlist.begin(); it != strlist.end(); ++it) {
TQStringList pieces = TQStringList::split("/", (*it));
TDENetworkSingleRouteConfiguration routeconfig;
routeconfig.ipAddress.setAddress(pieces[0]);
if (pieces.count() > 1) {
routeconfig.networkMask.fromCIDRMask(pieces[1].toUInt());
}
ret.append(routeconfig);
}
return ret;
} }
bool OpenVPNConfig::hasChanged() bool OpenVPNConfig::hasChanged()
@ -526,7 +562,7 @@ OpenVPNAuthentication::~OpenVPNAuthentication()
} }
void OpenVPNAuthentication::setVPNData(const TQStringList& /*routes*/, const TQMap<TQString, TQString>& properties) void OpenVPNAuthentication::setVPNData(TDENetworkSingleRouteConfigurationList& /*routes*/, TDENetworkSettingsMap& properties, TDENetworkSettingsMap& secrets)
{ {
// find the connection type property // find the connection type property
for(TQMap<TQString, TQString>::ConstIterator it = properties.begin(); it != properties.end(); ++it) for(TQMap<TQString, TQString>::ConstIterator it = properties.begin(); it != properties.end(); ++it)
@ -539,7 +575,7 @@ void OpenVPNAuthentication::setVPNData(const TQStringList& /*routes*/, const TQM
} }
} }
TQMap<TQString, TQString> OpenVPNAuthentication::getPasswords() TDENetworkSettingsMap OpenVPNAuthentication::getPasswords()
{ {
TQMap<TQString, TQString> pwds; TQMap<TQString, TQString> pwds;
if ((_connectionType == OpenVPNConnectionType::PASSWORD) || (_connectionType == OpenVPNConnectionType::X509USERPASS)) if ((_connectionType == OpenVPNConnectionType::PASSWORD) || (_connectionType == OpenVPNConnectionType::X509USERPASS))
@ -550,10 +586,10 @@ TQMap<TQString, TQString> OpenVPNAuthentication::getPasswords()
return pwds; return pwds;
} }
void OpenVPNAuthentication::setPasswords(TQString name, TQString value) { void OpenVPNAuthentication::setPasswords(TDENetworkSettingsMap secrets) {
if (name == TQString("password")) { if (secrets.contains("password")) {
_openvpnAuth->editUserPassword->erase(); _openvpnAuth->editUserPassword->erase();
_openvpnAuth->editUserPassword->insert(value); _openvpnAuth->editUserPassword->insert(secrets["password"]);
} }
} }
@ -564,3 +600,4 @@ bool OpenVPNAuthentication::needsUserInteraction()
return false; return false;
} }
#include "tdenetman-openvpn.moc"

@ -31,7 +31,7 @@
#include <tqlayout.h> #include <tqlayout.h>
#include <kprocess.h> #include <kprocess.h>
#include "knetworkmanager-vpnplugin.h" #include "tdenetman-vpnplugin.h"
#include "openvpnprop.h" #include "openvpnprop.h"
#include "openvpnauth.h" #include "openvpnauth.h"
@ -68,9 +68,10 @@ class OpenVPNConfig : public VPNConfigWidget
Q_OBJECT Q_OBJECT
public: public:
void setVPNData(const TQStringList& routes, const TQMap<TQString, TQString>& properties); void setVPNData(TDENetworkSingleRouteConfigurationList& routes, TDENetworkSettingsMap& properties, TDENetworkSettingsMap& secrets);
TQMap<TQString, TQString> getVPNProperties(); TDENetworkSettingsMap getVPNProperties();
TQStringList getVPNRoutes(); TDENetworkSettingsMap getVPNSecrets();
TDENetworkSingleRouteConfigurationList getVPNRoutes();
bool hasChanged(); bool hasChanged();
bool isValid(TQStringList&); bool isValid(TQStringList&);
@ -86,6 +87,9 @@ class OpenVPNConfig : public VPNConfigWidget
void getCipherModes(); void getCipherModes();
TQString findOpenVPNBinary(); TQString findOpenVPNBinary();
TDENetworkSettingsMap m_vpnProperties;
TDENetworkSettingsMap m_vpnSecrets;
protected slots: protected slots:
void languageChange(); void languageChange();
}; };
@ -97,9 +101,9 @@ class OpenVPNAuthentication : public VPNAuthenticationWidget
public: public:
OpenVPNAuthentication(TQWidget* parent = NULL, char* name = NULL); OpenVPNAuthentication(TQWidget* parent = NULL, char* name = NULL);
~OpenVPNAuthentication(); ~OpenVPNAuthentication();
void setVPNData(const TQStringList&, const TQMap<TQString, TQString>&); void setVPNData(TDENetworkSingleRouteConfigurationList& routes, TDENetworkSettingsMap& properties, TDENetworkSettingsMap& secrets);
TQMap<TQString, TQString> getPasswords(); TDENetworkSettingsMap getPasswords();
void setPasswords(TQString name, TQString value); void setPasswords(TDENetworkSettingsMap secrets);
bool needsUserInteraction(); bool needsUserInteraction();
private: private:

@ -3,11 +3,11 @@ Encoding=UTF-8
Type=Service Type=Service
Icon= Icon=
ServiceTypes=TDENetworkManager/VPNPlugin ServiceTypes=TDENetworkManager/VPNPlugin
X-TDE-Library=knetworkmanager_openvpn X-TDE-Library=tdenetman_openvpn
X-NetworkManager-Services=openvpn X-NetworkManager-Services=openvpn
X-TDE-PluginInfo-Author=Helmut Schaa X-TDE-PluginInfo-Author=Timothy Pearson
X-TDE-PluginInfo-Email=hschaa@suse.de X-TDE-PluginInfo-Email=kb9vqf@pearsoncomputing.net
X-TDE-PluginInfo-Name=knetworkmanager_openvpn X-TDE-PluginInfo-Name=tdenetman_openvpn
X-TDE-PluginInfo-Version=0.1 X-TDE-PluginInfo-Version=0.1
X-TDE-PluginInfo-Website= X-TDE-PluginInfo-Website=
X-TDE-PluginInfo-Category=VPNService X-TDE-PluginInfo-Category=VPNService
Loading…
Cancel
Save