1 //=============================================================================
2 //
3 //   File : OptionsWidget_proxy.cpp
4 //   Creation date : Mon Jun 24 2000 22:02:11 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2000-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #include "OptionsWidget_proxy.h"
26 
27 #include "KviLocale.h"
28 #include "KviIconManager.h"
29 #include "KviProxy.h"
30 #include "KviProxyDataBase.h"
31 #include "KviIpEditor.h"
32 #include "KviNetUtils.h"
33 #include "kvi_settings.h"
34 #include "KviOptions.h"
35 #include "KviTalGroupBox.h"
36 #include "KviTalToolTip.h"
37 
38 #include <QLabel>
39 #include <QLineEdit>
40 #include <QComboBox>
41 #include <QCursor>
42 #include <QIcon>
43 #include <QToolButton>
44 #include <QMenu>
45 
46 #include <memory>
47 #include <utility>
48 #include <vector>
49 
ProxyOptionsTreeWidgetItem(QTreeWidget * parent,const QPixmap & pm,KviProxy * prx)50 ProxyOptionsTreeWidgetItem::ProxyOptionsTreeWidgetItem(QTreeWidget * parent, const QPixmap & pm, KviProxy * prx)
51     : QTreeWidgetItem(parent)
52 {
53 	qDebug("Creating item");
54 	setText(0, prx->hostname());
55 	setIcon(0, QIcon(pm));
56 	m_pProxyData = new KviProxy(*prx);
57 }
58 
~ProxyOptionsTreeWidgetItem()59 ProxyOptionsTreeWidgetItem::~ProxyOptionsTreeWidgetItem()
60 {
61 	qDebug("Deleting item");
62 	delete m_pProxyData;
63 }
64 
OptionsWidget_proxy(QWidget * parent)65 OptionsWidget_proxy::OptionsWidget_proxy(QWidget * parent)
66     : KviOptionsWidget(parent, "proxy_options_widget")
67 {
68 	createLayout();
69 
70 	m_pUseProxySelector = addBoolSelector(0, 0, 1, 0, __tr2qs_ctx("Use proxy for all connections", "options"), KviOption_boolUseProxyHost);
71 	QString szTip = __tr2qs_ctx("When enabled, the selected proxy will be used as the default for all connections. "
72 	                            "An alternative option to define a specific per-server proxy, is also located "
73 	                            "in the advanced server dialog in the connection tab.", "options");
74 
75 	mergeTip(m_pUseProxySelector, szTip);
76 
77 	m_pTreeWidget = new QTreeWidget(this);
78 	addWidgetToLayout(m_pTreeWidget, 0, 1, 0, 1);
79 	m_pTreeWidget->setHeaderLabel(__tr2qs_ctx("Proxy", "options"));
80 	m_pTreeWidget->setRootIsDecorated(true);
81 	m_pTreeWidget->setAllColumnsShowFocus(true);
82 	m_pTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
83 
84 	connect(m_pTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
85 	    this, SLOT(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
86 	m_pTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
87 	connect(m_pTreeWidget, SIGNAL(customContextMenuRequested(const QPoint &)),
88 	    this, SLOT(customContextMenuRequested(const QPoint &)));
89 
90 	QString tiptxt = __tr2qs_ctx("This is the list of available proxy servers.<br>"
91 	                             "Right-click on the list to add or remove proxies.", "options");
92 
93 	mergeTip(m_pTreeWidget, tiptxt);
94 	mergeTip(m_pTreeWidget->viewport(), tiptxt);
95 
96 	KviTalVBox * vbox = new KviTalVBox(this);
97 	addWidgetToLayout(vbox, 1, 1, 1, 1);
98 
99 	QToolButton * tb = new QToolButton(vbox);
100 	tb->setIcon(QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::NewProxy))));
101 	tb->setAutoRaise(true);
102 	connect(tb, SIGNAL(clicked()), this, SLOT(newProxy()));
103 	mergeTip(tb, __tr2qs_ctx("New proxy", "options"));
104 
105 	tb = new QToolButton(vbox);
106 	tb->setIcon(QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Remove))));
107 	tb->setAutoRaise(true);
108 	connect(tb, SIGNAL(clicked()), this, SLOT(removeCurrent()));
109 	mergeTip(tb, __tr2qs_ctx("Remove proxy", "options"));
110 
111 	QFrame * lll = new QFrame(vbox);
112 	vbox->setStretchFactor(lll, 100);
113 
114 	KviTalGroupBox * gbox = addGroupBox(0, 2, 1, 2, Qt::Horizontal, __tr2qs_ctx("Configuration", "options"));
115 
116 	m_pProxyLabel = new QLabel(__tr2qs_ctx("Proxy:", "options"), gbox);
117 	m_pProxyEdit = new QLineEdit(gbox);
118 	m_pPortLabel = new QLabel(__tr2qs_ctx("Port:", "options"), gbox);
119 	m_pPortEdit = new QLineEdit(gbox);
120 	m_pIpLabel = new QLabel(__tr2qs_ctx("IP address:", "options"), gbox);
121 	m_pIpEditor = new KviIpEditor(gbox, KviIpEditor::IPv4);
122 	m_pUserLabel = new QLabel(__tr2qs_ctx("Username:", "options"), gbox);
123 	m_pUserEdit = new QLineEdit(gbox);
124 	m_pPassLabel = new QLabel(__tr2qs_ctx("Password:", "options"), gbox);
125 	m_pPassEdit = new QLineEdit(gbox);
126 	m_pProtocolLabel = new QLabel(__tr2qs_ctx("Protocol:", "options"), gbox);
127 	m_pProtocolBox = new QComboBox(gbox);
128 
129 	QStringList l = KviProxy::getSupportedProtocolNames();
130 
131 	m_pProtocolBox->addItems(l);
132 
133 	m_pIPv6Check = new QCheckBox(__tr2qs_ctx("Use IPv6 protocol", "options"), gbox);
134 	connect(m_pIPv6Check, SIGNAL(toggled(bool)), this, SLOT(ipV6CheckToggled(bool)));
135 #ifndef COMPILE_IPV6_SUPPORT
136 	m_pIPv6Check->setEnabled(false);
137 #endif
138 	m_pLastEditedItem = nullptr;
139 
140 	fillProxyList();
141 
142 	layout()->setRowStretch(0, 1);
143 	layout()->setColumnStretch(0, 1);
144 
145 	m_pContextPopup = new QMenu(this);
146 }
147 
enableDisableUseProxySelector()148 void OptionsWidget_proxy::enableDisableUseProxySelector()
149 {
150 	m_pUseProxySelector->setEnabled(m_pTreeWidget->currentItem());
151 	if(m_pTreeWidget->topLevelItemCount() < 1)
152 		m_pUseProxySelector->setChecked(false);
153 }
154 
ipV6CheckToggled(bool bEnabled)155 void OptionsWidget_proxy::ipV6CheckToggled(bool bEnabled)
156 {
157 	m_pIpEditor->setAddressType(bEnabled ? KviIpEditor::IPv6 : KviIpEditor::IPv4);
158 }
159 
fillProxyList()160 void OptionsWidget_proxy::fillProxyList()
161 {
162 	ProxyOptionsTreeWidgetItem * prx;
163 
164 	std::vector<std::unique_ptr<KviProxy>> & l = g_pProxyDataBase->proxyList();
165 
166 	for(auto & p : l)
167 	{
168 		prx = new ProxyOptionsTreeWidgetItem(m_pTreeWidget, *(g_pIconManager->getSmallIcon(KviIconManager::Proxy)), p.get());
169 		if(p.get() == g_pProxyDataBase->currentProxy())
170 		{
171 			prx->setSelected(true);
172 			m_pTreeWidget->setCurrentItem(prx);
173 			m_pTreeWidget->scrollToItem(prx);
174 		}
175 	}
176 	if(!(g_pProxyDataBase->currentProxy()))
177 		currentItemChanged(nullptr, nullptr);
178 
179 	enableDisableUseProxySelector();
180 }
181 
currentItemChanged(QTreeWidgetItem * it,QTreeWidgetItem *)182 void OptionsWidget_proxy::currentItemChanged(QTreeWidgetItem * it, QTreeWidgetItem *)
183 {
184 	if(m_pLastEditedItem)
185 		saveLastItem();
186 	m_pLastEditedItem = (ProxyOptionsTreeWidgetItem *)it;
187 
188 	m_pProxyLabel->setEnabled(m_pLastEditedItem);
189 	m_pProxyEdit->setEnabled(m_pLastEditedItem);
190 	m_pIpLabel->setEnabled(m_pLastEditedItem);
191 	m_pIpEditor->setEnabled(m_pLastEditedItem);
192 	m_pUserLabel->setEnabled(m_pLastEditedItem);
193 	m_pUserEdit->setEnabled(m_pLastEditedItem);
194 	m_pPassLabel->setEnabled(m_pLastEditedItem);
195 	m_pPassEdit->setEnabled(m_pLastEditedItem);
196 	m_pProtocolLabel->setEnabled(m_pLastEditedItem);
197 	m_pProtocolBox->setEnabled(m_pLastEditedItem);
198 	m_pPortLabel->setEnabled(m_pLastEditedItem);
199 	m_pPortEdit->setEnabled(m_pLastEditedItem);
200 
201 #ifdef COMPILE_IPV6_SUPPORT
202 	m_pIPv6Check->setEnabled(m_pLastEditedItem);
203 #else
204 	m_pIPv6Check->setEnabled(false);
205 #endif
206 	if(m_pLastEditedItem)
207 	{
208 		m_pProxyEdit->setText(m_pLastEditedItem->m_pProxyData->hostname());
209 
210 		for(int i = 0; i < m_pProtocolBox->count(); i++)
211 		{
212 			KviCString txt = m_pProtocolBox->itemText(i);
213 			if(kvi_strEqualCI(m_pLastEditedItem->m_pProxyData->protocolName().toUtf8().data(), txt.ptr()))
214 			{
215 				m_pProtocolBox->setCurrentIndex(i);
216 				break;
217 			}
218 		}
219 
220 #ifdef COMPILE_IPV6_SUPPORT
221 		m_pIPv6Check->setChecked(m_pLastEditedItem->m_pProxyData->isIPv6());
222 		m_pIpEditor->setAddressType(m_pLastEditedItem->m_pProxyData->isIPv6() ? KviIpEditor::IPv6 : KviIpEditor::IPv4);
223 #else
224 		m_pIPv6Check->setChecked(false);
225 		m_pIpEditor->setAddressType(KviIpEditor::IPv4);
226 #endif
227 		if(!m_pIpEditor->setAddress(m_pLastEditedItem->m_pProxyData->ip()))
228 		{
229 #ifdef COMPILE_IPV6_SUPPORT
230 			m_pIpEditor->setAddress(m_pLastEditedItem->m_pProxyData->isIPv6() ? "0:0:0:0:0:0:0:0" : "0.0.0.0");
231 #else
232 			m_pIpEditor->setAddress("0.0.0.0");
233 #endif
234 		}
235 
236 		m_pUserEdit->setText(m_pLastEditedItem->m_pProxyData->user());
237 		m_pPassEdit->setText(m_pLastEditedItem->m_pProxyData->pass());
238 		KviCString tmp(KviCString::Format, "%u", m_pLastEditedItem->m_pProxyData->port());
239 		m_pPortEdit->setText(tmp.ptr());
240 	}
241 	else
242 	{
243 		m_pProxyEdit->setText("");
244 		m_pUserEdit->setText("");
245 		m_pPassEdit->setText("");
246 		m_pPortEdit->setText("");
247 		m_pIpEditor->setAddress("0.0.0.0");
248 		m_pIPv6Check->setEnabled(false);
249 	}
250 	enableDisableUseProxySelector();
251 }
252 
saveLastItem()253 void OptionsWidget_proxy::saveLastItem()
254 {
255 	if(m_pLastEditedItem)
256 	{
257 		QString tmp = m_pProxyEdit->text();
258 		if(tmp.isEmpty())
259 			tmp = "irc.unknown.net";
260 
261 		m_pLastEditedItem->setText(0, tmp);
262 		m_pLastEditedItem->m_pProxyData->setHostname(tmp);
263 #ifdef COMPILE_IPV6_SUPPORT
264 		m_pLastEditedItem->m_pProxyData->setIPv6(m_pIPv6Check->isChecked());
265 #else
266 		m_pLastEditedItem->m_pProxyData->setIPv6(false);
267 #endif
268 		m_pLastEditedItem->m_pProxyData->setIp("");
269 
270 		if(m_pIpEditor->isValid())
271 		{
272 			QString tmpAddr = m_pIpEditor->address();
273 #ifdef COMPILE_IPV6_SUPPORT
274 			if(m_pIPv6Check->isChecked())
275 			{
276 				if(tmpAddr != "::" && KviNetUtils::isValidStringIPv6(tmpAddr))
277 					m_pLastEditedItem->m_pProxyData->setIp(tmpAddr);
278 			}
279 			else
280 			{
281 #endif
282 				if(tmpAddr != "0.0.0.0" && KviNetUtils::isValidStringIp(tmpAddr))
283 					m_pLastEditedItem->m_pProxyData->setIp(tmpAddr);
284 #ifdef COMPILE_IPV6_SUPPORT
285 			}
286 #endif
287 		}
288 		m_pLastEditedItem->m_pProxyData->setPass(m_pPassEdit->text());
289 		m_pLastEditedItem->m_pProxyData->setUser(m_pUserEdit->text());
290 		tmp = m_pPortEdit->text();
291 		bool bOk;
292 		kvi_u32_t uPort = tmp.toUInt(&bOk);
293 		if(!bOk)
294 			uPort = 1080;
295 		m_pLastEditedItem->m_pProxyData->setPort(uPort);
296 		m_pLastEditedItem->m_pProxyData->setNamedProtocol(m_pProtocolBox->currentText());
297 	}
298 }
299 
commit()300 void OptionsWidget_proxy::commit()
301 {
302 	saveLastItem();
303 	g_pProxyDataBase->clear();
304 
305 	ProxyOptionsTreeWidgetItem * it;
306 
307 	for(int i = 0; i < m_pTreeWidget->topLevelItemCount(); i++)
308 	{
309 		it = (ProxyOptionsTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
310 		QString tmp = it->text(0);
311 		if(!tmp.isEmpty())
312 		{
313 			KviProxy *const proxy = new KviProxy(*(it->m_pProxyData));
314 
315 			g_pProxyDataBase->insertProxy(std::unique_ptr<KviProxy>(proxy));
316 
317 			if(it == m_pLastEditedItem)
318 				g_pProxyDataBase->setCurrentProxy(proxy);
319 		}
320 	}
321 
322 	if(!g_pProxyDataBase->currentProxy() && !g_pProxyDataBase->proxyList().empty())
323 		g_pProxyDataBase->setCurrentProxy(g_pProxyDataBase->proxyList().front().get());
324 
325 	KviOptionsWidget::commit();
326 }
327 
customContextMenuRequested(const QPoint & pos)328 void OptionsWidget_proxy::customContextMenuRequested(const QPoint & pos)
329 {
330 	QTreeWidgetItem * it = (QTreeWidgetItem *)m_pTreeWidget->itemAt(pos);
331 	m_pContextPopup->clear();
332 	m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::NewProxy)), __tr2qs_ctx("&New Proxy", "options"), this, SLOT(newProxy()));
333 	m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Remove)), __tr2qs_ctx("Re&move Proxy", "options"), this, SLOT(removeCurrent()))
334 	    ->setEnabled(it);
335 	m_pContextPopup->popup(QCursor::pos());
336 }
337 
newProxy()338 void OptionsWidget_proxy::newProxy()
339 {
340 	KviProxy prx;
341 	ProxyOptionsTreeWidgetItem * it = new ProxyOptionsTreeWidgetItem(m_pTreeWidget, *(g_pIconManager->getSmallIcon(KviIconManager::Proxy)), &prx);
342 	it->setSelected(true);
343 	m_pTreeWidget->setCurrentItem(it);
344 	m_pTreeWidget->scrollToItem(it);
345 }
346 
removeCurrent()347 void OptionsWidget_proxy::removeCurrent()
348 {
349 	if(m_pLastEditedItem)
350 	{
351 		QTreeWidgetItem * tmp = m_pLastEditedItem;
352 		m_pLastEditedItem = nullptr;
353 		delete tmp;
354 
355 		QTreeWidgetItem * it = (QTreeWidgetItem *)m_pTreeWidget->topLevelItem(0);
356 		if(it)
357 		{
358 			it->setSelected(true);
359 		}
360 		else
361 		{
362 			currentItemChanged(nullptr, nullptr);
363 		}
364 	}
365 }
366