00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "NetViewer.h"
00018 #include "RouterInfoDialog.h"
00019 #include "RouterListItem.h"
00020 #include "Vidalia.h"
00021 #include "VMessageBox.h"
00022
00023 #include <QMessageBox>
00024 #include <QHeaderView>
00025
00026 #define IMG_MOVE ":/images/22x22/move-map.png"
00027 #define IMG_ZOOMIN ":/images/22x22/zoom-in.png"
00028 #define IMG_ZOOMOUT ":/images/22x22/zoom-out.png"
00029
00030
00031
00032
00033 #define MIN_RESOLVE_QUEUE_DELAY (10*1000)
00034
00035
00036 #define MAX_RESOLVE_QUEUE_DELAY (30*1000)
00037
00038
00039
00040
00041
00042 NetViewer::NetViewer(QWidget *parent)
00043 : VidaliaWindow("NetViewer", parent)
00044 {
00045
00046 ui.setupUi(this);
00047
00048 #if defined(Q_WS_MAC)
00049 ui.actionHelp->setShortcut(QString("Ctrl+?"));
00050 #endif
00051
00052
00053 ui.actionClose->setShortcut(QString("Esc"));
00054 Vidalia::createShortcut("Ctrl+W", this, ui.actionClose, SLOT(trigger()));
00055
00056
00057 _torControl = Vidalia::torControl();
00058 connect(_torControl, SIGNAL(authenticated()),
00059 this, SLOT(onAuthenticated()));
00060 connect(_torControl, SIGNAL(disconnected()),
00061 this, SLOT(onDisconnected()));
00062
00063 _torControl->setEvent(TorEvents::CircuitStatus);
00064 connect(_torControl, SIGNAL(circuitStatusChanged(Circuit)),
00065 this, SLOT(addCircuit(Circuit)));
00066
00067 _torControl->setEvent(TorEvents::StreamStatus);
00068 connect(_torControl, SIGNAL(streamStatusChanged(Stream)),
00069 this, SLOT(addStream(Stream)));
00070
00071 _torControl->setEvent(TorEvents::AddressMap);
00072 connect(_torControl, SIGNAL(addressMapped(QString, QString, QDateTime)),
00073 this, SLOT(addressMapped(QString, QString, QDateTime)));
00074
00075 _torControl->setEvent(TorEvents::NewDescriptor);
00076 connect(_torControl, SIGNAL(newDescriptors(QStringList)),
00077 this, SLOT(newDescriptors(QStringList)));
00078
00079
00080 ui.treeRouterList->header()->
00081 resizeSection(RouterListWidget::StatusColumn, 25);
00082 ui.treeRouterList->header()->
00083 resizeSection(RouterListWidget::CountryColumn, 25);
00084 ui.treeCircuitList->header()->
00085 resizeSection(CircuitListWidget::ConnectionColumn, 235);
00086
00087
00088 #if defined(USE_MARBLE)
00089 _map = new TorMapWidget();
00090 connect(_map, SIGNAL(displayRouterInfo(QString)),
00091 this, SLOT(displayRouterInfo(QString)));
00092 connect(ui.actionZoomFullScreen, SIGNAL(triggered()),
00093 this, SLOT(toggleFullScreen()));
00094 Vidalia::createShortcut("ESC", _map, this, SLOT(toggleFullScreen()));
00095 #else
00096 _map = new TorMapImageView();
00097 ui.actionZoomFullScreen->setVisible(false);
00098 #endif
00099 ui.gridLayout->addWidget(_map);
00100
00101
00102
00103 connect(ui.actionZoomIn, SIGNAL(triggered()), this, SLOT(zoomIn()));
00104 connect(ui.actionZoomOut, SIGNAL(triggered()), this, SLOT(zoomOut()));
00105 connect(ui.actionZoomToFit, SIGNAL(triggered()), _map, SLOT(zoomToFit()));
00106
00107
00108
00109
00110 _refreshTimer.setInterval(60*60*1000);
00111 connect(&_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
00112
00113
00114
00115
00116 _minResolveQueueTimer.setSingleShot(true);
00117 connect(&_minResolveQueueTimer, SIGNAL(timeout()), this, SLOT(resolve()));
00118 _maxResolveQueueTimer.setSingleShot(true);
00119 connect(&_maxResolveQueueTimer, SIGNAL(timeout()), this, SLOT(resolve()));
00120
00121
00122 connect(ui.actionHelp, SIGNAL(triggered()), this, SLOT(help()));
00123 connect(ui.actionRefresh, SIGNAL(triggered()), this, SLOT(refresh()));
00124 connect(ui.treeRouterList, SIGNAL(routerSelected(QList<RouterDescriptor>)),
00125 this, SLOT(routerSelected(QList<RouterDescriptor>)));
00126 connect(ui.treeRouterList, SIGNAL(zoomToRouter(QString)),
00127 _map, SLOT(zoomToRouter(QString)));
00128 connect(ui.treeCircuitList, SIGNAL(circuitSelected(Circuit)),
00129 this, SLOT(circuitSelected(Circuit)));
00130 connect(ui.treeCircuitList, SIGNAL(circuitRemoved(CircuitId)),
00131 _map, SLOT(removeCircuit(CircuitId)));
00132 connect(ui.treeCircuitList, SIGNAL(zoomToCircuit(CircuitId)),
00133 _map, SLOT(zoomToCircuit(CircuitId)));
00134 connect(ui.treeCircuitList, SIGNAL(closeCircuit(CircuitId)),
00135 _torControl, SLOT(closeCircuit(CircuitId)));
00136 connect(ui.treeCircuitList, SIGNAL(closeStream(StreamId)),
00137 _torControl, SLOT(closeStream(StreamId)));
00138
00139
00140 connect(&_geoip, SIGNAL(resolved(int, QList<GeoIp>)),
00141 this, SLOT(resolved(int, QList<GeoIp>)));
00142 }
00143
00144
00145 void
00146 NetViewer::retranslateUi()
00147 {
00148 ui.retranslateUi(this);
00149 ui.treeRouterList->retranslateUi();
00150 ui.treeCircuitList->retranslateUi();
00151
00152 if (ui.treeRouterList->selectedItems().size()) {
00153 QList<RouterDescriptor> routers;
00154 foreach (QTreeWidgetItem *item, ui.treeRouterList->selectedItems()) {
00155 routers << dynamic_cast<RouterListItem *>(item)->descriptor();
00156 }
00157 ui.textRouterInfo->display(routers);
00158 } else if (ui.treeCircuitList->selectedItems().size()) {
00159 QList<RouterDescriptor> routers;
00160 QTreeWidgetItem *item = ui.treeCircuitList->selectedItems()[0];
00161 Circuit circuit = dynamic_cast<CircuitItem*>(item)->circuit();
00162 foreach (QString id, circuit.routerIDs()) {
00163 RouterListItem *item = ui.treeRouterList->findRouterById(id);
00164 if (item)
00165 routers.append(item->descriptor());
00166 }
00167 ui.textRouterInfo->display(routers);
00168 }
00169 }
00170
00171
00172
00173 void
00174 NetViewer::showWindow()
00175 {
00176 if (!_resolveQueue.isEmpty()) {
00177 _minResolveQueueTimer.start(MIN_RESOLVE_QUEUE_DELAY);
00178 _maxResolveQueueTimer.start(MAX_RESOLVE_QUEUE_DELAY);
00179 }
00180 VidaliaWindow::showWindow();
00181 }
00182
00183
00184 void
00185 NetViewer::onAuthenticated()
00186 {
00187 _geoip.setSocksHost(_torControl->getSocksAddress(),
00188 _torControl->getSocksPort());
00189 refresh();
00190 _refreshTimer.start();
00191 ui.actionRefresh->setEnabled(true);
00192 }
00193
00194
00195 void
00196 NetViewer::onDisconnected()
00197 {
00198 clear();
00199 _refreshTimer.stop();
00200 ui.actionRefresh->setEnabled(false);
00201 }
00202
00203
00204 void
00205 NetViewer::refresh()
00206 {
00207
00208 ui.actionRefresh->setEnabled(false);
00209
00210
00211 clear();
00212
00213
00214 loadNetworkStatus();
00215
00216 loadAddressMap();
00217
00218 loadConnections();
00219
00220
00221 ui.actionRefresh->setEnabled(true);
00222 }
00223
00224
00225 void
00226 NetViewer::clear()
00227 {
00228
00229 _resolveMap.clear();
00230 _resolveQueue.clear();
00231
00232 _map->clear();
00233 _map->update();
00234
00235 _addressMap.clear();
00236
00237 ui.treeRouterList->clearRouters();
00238 ui.treeCircuitList->clearCircuits();
00239 ui.textRouterInfo->clear();
00240 }
00241
00242
00243 void
00244 NetViewer::loadAddressMap()
00245 {
00246
00247
00248 _addressMap = _torControl->getAddressMap().reverse();
00249 }
00250
00251
00252 void
00253 NetViewer::loadConnections()
00254 {
00255
00256 CircuitList circuits = _torControl->getCircuits();
00257 foreach (Circuit circuit, circuits) {
00258 addCircuit(circuit);
00259 }
00260
00261 StreamList streams = _torControl->getStreams();
00262 foreach (Stream stream, streams) {
00263 addStream(stream);
00264 }
00265
00266
00267 _map->update();
00268 }
00269
00270
00271 void
00272 NetViewer::addCircuit(const Circuit &circuit)
00273 {
00274
00275 ui.treeCircuitList->addCircuit(circuit);
00276
00277 _map->addCircuit(circuit.id(), circuit.routerIDs());
00278 }
00279
00280
00281 void
00282 NetViewer::addStream(const Stream &stream)
00283 {
00284 QString target = stream.targetAddress();
00285 QHostAddress addr(target);
00286
00287
00288
00289 if (!addr.isNull() && _addressMap.isMapped(target)) {
00290
00291
00292 ui.treeCircuitList->addStream(
00293 Stream(stream.id(), stream.status(), stream.circuitId(),
00294 _addressMap.mappedTo(target), stream.targetPort()));
00295 } else {
00296 ui.treeCircuitList->addStream(stream);
00297 }
00298 }
00299
00300 void
00301 NetViewer::addressMapped(const QString &from, const QString &to,
00302 const QDateTime &expires)
00303 {
00304 _addressMap.add(to, from, expires);
00305 }
00306
00307
00308 void
00309 NetViewer::help()
00310 {
00311 emit helpRequested("netview");
00312 }
00313
00314
00315
00316 void
00317 NetViewer::loadNetworkStatus()
00318 {
00319 NetworkStatus networkStatus = _torControl->getNetworkStatus();
00320 foreach (RouterStatus rs, networkStatus) {
00321 if (!rs.isRunning())
00322 continue;
00323
00324 RouterDescriptor rd = _torControl->getRouterDescriptor(rs.id());
00325 if (!rd.isEmpty())
00326 addRouter(rd);
00327 }
00328 }
00329
00330
00331
00332 void
00333 NetViewer::addRouter(const RouterDescriptor &rd)
00334 {
00335
00336 ui.treeRouterList->addRouter(rd);
00337
00338
00339
00340
00341 if (_torControl->getTorVersion() >= 0x020013) {
00342 DescriptorAnnotations annotations =
00343 _torControl->getDescriptorAnnotations(rd.id());
00344 if (!annotations.contains("purpose"))
00345 addToResolveQueue(rd.ip(), rd.id());
00346 } else {
00347 addToResolveQueue(rd.ip(), rd.id());
00348 }
00349 }
00350
00351
00352
00353
00354 void
00355 NetViewer::newDescriptors(const QStringList &ids)
00356 {
00357 foreach (QString id, ids) {
00358 RouterDescriptor rd = _torControl->getRouterDescriptor(id);
00359 if (!rd.isEmpty())
00360 addRouter(rd);
00361 }
00362 }
00363
00364
00365 void
00366 NetViewer::addToResolveQueue(const QHostAddress &ip, const QString &id)
00367 {
00368 QString ipstr = ip.toString();
00369 if (!_resolveMap.values(ipstr).contains(id)) {
00370
00371 _resolveMap.insertMulti(ipstr, id);
00372 }
00373
00374 if (!_resolveQueue.contains(ip) && !_geoip.resolveFromCache(ip)) {
00375
00376 _resolveQueue << ip;
00377
00378
00379
00380 _minResolveQueueTimer.start(MIN_RESOLVE_QUEUE_DELAY);
00381
00382
00383
00384
00385 if (_resolveQueue.size() == 1) {
00386 _maxResolveQueueTimer.start(MAX_RESOLVE_QUEUE_DELAY);
00387 }
00388 }
00389 }
00390
00391
00392
00393 void
00394 NetViewer::circuitSelected(const Circuit &circuit)
00395 {
00396
00397 ui.treeRouterList->deselectAll();
00398 ui.textRouterInfo->clear();
00399 _map->deselectAll();
00400
00401
00402 _map->selectCircuit(circuit.id());
00403
00404 QList<RouterDescriptor> routers;
00405
00406 foreach (QString id, circuit.routerIDs()) {
00407
00408 RouterListItem *item = ui.treeRouterList->findRouterById(id);
00409 if (item)
00410 routers.append(item->descriptor());
00411 }
00412
00413 ui.textRouterInfo->display(routers);
00414 }
00415
00416
00417 void
00418 NetViewer::routerSelected(const QList<RouterDescriptor> &routers)
00419 {
00420 _map->deselectAll();
00421 ui.textRouterInfo->clear();
00422 ui.textRouterInfo->display(routers);
00423
00424
00425
00426
00427
00428 if (routers.size() == 1)
00429 _map->selectRouter(routers[0].id());
00430 }
00431
00432
00433 void
00434 NetViewer::resolve()
00435 {
00436 if (!_resolveQueue.isEmpty()) {
00437
00438
00439 if (isVisible() ||
00440 (_resolveQueue.size() >= ui.treeRouterList->topLevelItemCount()/4)) {
00441 vInfo("Sending GeoIP request for %1 IP addresses.")
00442 .arg(_resolveQueue.size());
00443
00444 _geoip.resolve(_resolveQueue);
00445 _resolveQueue.clear();
00446 }
00447 }
00448
00449
00450 _minResolveQueueTimer.stop();
00451 _maxResolveQueueTimer.stop();
00452 }
00453
00454
00455 void
00456 NetViewer::resolved(int id, const QList<GeoIp> &geoips)
00457 {
00458 Q_UNUSED(id);
00459
00460 QString ip;
00461 RouterListItem *router;
00462
00463 foreach (GeoIp geoip, geoips) {
00464
00465 ip = geoip.ip().toString();
00466 QList<QString> ids = _resolveMap.values(ip);
00467 _resolveMap.remove(ip);
00468
00469
00470
00471 foreach (QString id, ids) {
00472 router = ui.treeRouterList->findRouterById(id);
00473 if (router) {
00474
00475 router->setLocation(geoip);
00476
00477 _map->addRouter(router->descriptor(), geoip);
00478 }
00479 }
00480 }
00481
00482
00483 foreach (Circuit circuit, ui.treeCircuitList->circuits()) {
00484 _map->addCircuit(circuit.id(), circuit.routerIDs());
00485 }
00486
00487
00488 _map->update();
00489 }
00490
00491
00492
00493
00494 void
00495 NetViewer::displayRouterInfo(const QString &id)
00496 {
00497 RouterInfoDialog dlg(_map->isFullScreen() ? static_cast<QWidget*>(_map)
00498 : static_cast<QWidget*>(this));
00499
00500
00501 QStringList rd = _torControl->getRouterDescriptorText(id);
00502 if (rd.isEmpty()) {
00503 VMessageBox::warning(this, tr("Relay Not Found"),
00504 tr("No details on the selected relay are available."),
00505 VMessageBox::Ok);
00506 return;
00507 }
00508
00509
00510 RouterStatus rs = _torControl->getRouterStatus(id);
00511
00512 dlg.setRouterInfo(rd, rs);
00513
00514
00515 RouterListItem *item = ui.treeRouterList->findRouterById(id);
00516 if (item)
00517 dlg.setLocation(item->location());
00518 else
00519 dlg.setLocation(tr("Unknown"));
00520
00521 dlg.exec();
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 void
00533 NetViewer::zoomIn()
00534 {
00535 #if defined(USE_MARBLE)
00536 _map->zoomViewBy(40);
00537 #else
00538 _map->zoomIn();
00539 #endif
00540 }
00541
00542
00543 void
00544 NetViewer::zoomOut()
00545 {
00546 #if defined(USE_MARBLE)
00547 _map->zoomViewBy(-40);
00548 #else
00549 _map->zoomOut();
00550 #endif
00551 }
00552
00553
00554
00555 void
00556 NetViewer::toggleFullScreen()
00557 {
00558 if (_map->isFullScreen()) {
00559
00560 ui.gridLayout->addWidget(_map);
00561 _map->setWindowState(_map->windowState() & ~Qt::WindowFullScreen);
00562 } else {
00563
00564
00565 _map->setParent(0);
00566 _map->setWindowState(_map->windowState() | Qt::WindowFullScreen);
00567 _map->show();
00568 }
00569 }
00570