StatusEventWidget.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file StatusEventWidget.h
00013 ** \version $Id: StatusEventWidget.cpp 4180 2009-12-13 21:29:25Z edmanm $
00014 ** \brief Displays information on Tor status events
00015 */
00016 
00017 #include "StatusEventWidget.h"
00018 #include "StatusEventItem.h"
00019 #include "StatusEventItemDelegate.h"
00020 #include "Vidalia.h"
00021 
00022 #include "TorEvents.h"
00023 #include "stringutil.h"
00024 
00025 #include <QTime>
00026 #include <QMenu>
00027 #include <QPainter>
00028 #include <QPixmap>
00029 #include <QStringList>
00030 #include <QObject>
00031 #include <QHeaderView>
00032 #include <QClipboard>
00033 
00034 bool compareStatusEventItems(const QTreeWidgetItem *a,
00035                              const QTreeWidgetItem *b)
00036 {
00037   return (*a < *b);
00038 }
00039 
00040 StatusEventWidget::StatusEventWidget(QWidget *parent)
00041   : QTreeWidget(parent)
00042 {
00043   TorControl *tc = Vidalia::torControl();
00044   tc->setEvent(TorEvents::GeneralStatus);
00045   tc->setEvent(TorEvents::ClientStatus);
00046   tc->setEvent(TorEvents::ServerStatus);
00047 
00048   connect(this, SIGNAL(customContextMenuRequested(QPoint)),
00049           this, SLOT(customContextMenuRequested(QPoint)));
00050   connect(tc, SIGNAL(authenticated()), this, SLOT(authenticated()));
00051   connect(tc, SIGNAL(disconnected()), this, SLOT(disconnected()));
00052   connect(tc, SIGNAL(dangerousTorVersion(tc::TorVersionStatus, QString,
00053                                          QStringList)),
00054           this, SLOT(dangerousTorVersion(tc::TorVersionStatus, QString,
00055                                          QStringList)));
00056   connect(tc, SIGNAL(circuitEstablished()), this, SLOT(circuitEstablished()));
00057   connect(tc, SIGNAL(bug(QString)), this, SLOT(bug(QString)));
00058   connect(tc, SIGNAL(clockSkewed(int, QString)),
00059           this, SLOT(clockSkewed(int, QString)));
00060   connect(tc, SIGNAL(dangerousPort(quint16, bool)),
00061           this, SLOT(dangerousPort(quint16, bool)));
00062   connect(tc, SIGNAL(socksError(tc::SocksError, QString)),
00063           this, SLOT(socksError(tc::SocksError, QString)));
00064   connect(tc, SIGNAL(externalAddressChanged(QHostAddress, QString)),
00065           this, SLOT(externalAddressChanged(QHostAddress, QString)));
00066   connect(tc, SIGNAL(dnsHijacked()), this, SLOT(dnsHijacked()));
00067   connect(tc, SIGNAL(dnsUseless()), this, SLOT(dnsUseless()));
00068   connect(tc, SIGNAL(checkingOrPortReachability(QHostAddress, quint16)),
00069           this, SLOT(checkingOrPortReachability(QHostAddress, quint16)));
00070   connect(tc, SIGNAL(orPortReachabilityFinished(QHostAddress, quint16, bool)),
00071           this, SLOT(orPortReachabilityFinished(QHostAddress, quint16, bool)));
00072   connect(tc, SIGNAL(checkingDirPortReachability(QHostAddress, quint16)),
00073           this, SLOT(checkingDirPortReachability(QHostAddress, quint16)));
00074   connect(tc, SIGNAL(dirPortReachabilityFinished(QHostAddress, quint16, bool)),
00075           this, SLOT(dirPortReachabilityFinished(QHostAddress, quint16, bool)));
00076   connect(tc, SIGNAL(serverDescriptorRejected(QHostAddress, quint16, QString)),
00077           this, SLOT(serverDescriptorRejected(QHostAddress, quint16, QString)));
00078   connect(tc, SIGNAL(serverDescriptorAccepted(QHostAddress, quint16)),
00079           this, SLOT(serverDescriptorAccepted(QHostAddress, quint16)));
00080 
00081   setItemDelegate(new StatusEventItemDelegate(this));
00082 }
00083 
00084 void
00085 StatusEventWidget::retranslateUi()
00086 {
00087   /* XXX: We need to store the untranslated text for each of the status
00088    *      event items, iterate through all items in the list, and then
00089    *      retranslate them. The trick is that some of the messages are
00090    *      generated dynamically based on data sent by Tor (which is NOT
00091    *      translated). Those messages we can't retranslate correctly
00092    *      without also storing the variables used to generate the message.
00093    */
00094 }
00095 
00096 void
00097 StatusEventWidget::setMaximumItemCount(int maximumItemCount)
00098 {
00099   _maximumItemCount = maximumItemCount;
00100 
00101   QTreeWidgetItem *item;
00102   Qt::SortOrder order = header()->sortIndicatorOrder();
00103   while (topLevelItemCount() > _maximumItemCount) {
00104     if (order == Qt::AscendingOrder)
00105       item = takeTopLevelItem(0);
00106     else
00107       item = takeTopLevelItem(topLevelItemCount()-1);
00108     if (item)
00109       delete item;
00110   }
00111 }
00112 
00113 int
00114 StatusEventWidget::maximumItemCount() const
00115 {
00116   return _maximumItemCount;
00117 }
00118 
00119 QStringList
00120 StatusEventWidget::selectedEvents() const
00121 {
00122   QString text;
00123   QStringList out;
00124   QList<QTreeWidgetItem *> items = selectedItems();
00125 
00126   // We have to sort the items since selectedItems() returns the order in
00127   // which the items were selected, not the order in which they appear in the
00128   // current list.
00129   qStableSort(items.begin(), items.end(), compareStatusEventItems);
00130 
00131   for (int i = 0; i < items.size(); i++) {
00132     StatusEventItem *event = dynamic_cast<StatusEventItem *>(items.at(i));
00133     if (event)
00134       out.append(event->toString());
00135   }
00136   return out;
00137 }
00138 
00139 QStringList
00140 StatusEventWidget::allEvents() const
00141 {
00142   QStringList out;
00143   QList<QTreeWidgetItem *> items;
00144 
00145   for (int i = 0; i < topLevelItemCount(); i++)
00146     items.append(topLevelItem(i));
00147 
00148   // Ensure the items are sorted in ascending order according to timestamp
00149   qStableSort(items.begin(), items.end(), compareStatusEventItems);
00150 
00151   for (int i = 0; i < items.size(); i++) {
00152     StatusEventItem *event = dynamic_cast<StatusEventItem *>(items.at(i));
00153     if (event)
00154       out.append(event->toString());
00155   }
00156   return out;
00157 }
00158 
00159 void
00160 StatusEventWidget::customContextMenuRequested(const QPoint &pos)
00161 {
00162   QMenu menu(this);
00163 
00164   StatusEventItem *item = dynamic_cast<StatusEventItem *>(itemAt(pos));
00165   if (! item || ! item->isSelected())
00166     return;
00167 
00168   QAction *copyAction = menu.addAction(QIcon(":/images/22x22/edit-copy.png"),
00169                                        tr("Copy to Clipboard"));
00170 
00171   QAction *action = menu.exec(mapToGlobal(pos));
00172   if (action == copyAction) {
00173     QStringList eventText = selectedEvents();
00174     if (! eventText.isEmpty())
00175       QApplication::clipboard()->setText(eventText.join("\n"));
00176   }
00177 }
00178 
00179 QList<StatusEventItem *>
00180 StatusEventWidget::find(const QString &text, bool highlight)
00181 {
00182   QList<StatusEventItem *> items;
00183 
00184   for (int i = 0; i < topLevelItemCount(); i++) {
00185     StatusEventItem *item = dynamic_cast<StatusEventItem *>(topLevelItem(i));
00186     if (! item)
00187       continue;
00188 
00189     if (item->title().contains(text, Qt::CaseInsensitive)
00190           || item->description().contains(text, Qt::CaseInsensitive)) {
00191       items.append(item);
00192       if (highlight)
00193         item->setSelected(true);
00194     } else if (highlight) {
00195       item->setSelected(false);
00196     }
00197   }
00198   return items;
00199 }
00200 
00201 void
00202 StatusEventWidget::addNotification(const QPixmap &icon,
00203                                    const QString &title,
00204                                    const QString &description,
00205                                    const QString &helpUrl)
00206 {
00207   // Check if we first need to remove the oldest item in the list in order
00208   // to avoid exceeding the maximum number of notification items
00209   if (topLevelItemCount() == maximumItemCount()) {
00210     QTreeWidgetItem *item;
00211     if (header()->sortIndicatorOrder() == Qt::AscendingOrder)
00212       item = takeTopLevelItem(0);
00213     else
00214       item = takeTopLevelItem(topLevelItemCount()-1);
00215     if (item)
00216       delete item;
00217   }
00218 
00219   // Create the new notification item
00220   StatusEventItem *item = new StatusEventItem(this);
00221   item->setTimestamp(QTime::currentTime());
00222   item->setIcon(icon);
00223   item->setTitle(title);
00224   item->setDescription(description);
00225   item->setHelpUrl(helpUrl);
00226   item->setToolTip(string_wrap(description, 80));
00227 
00228   // Add the new item to the list and ensure it is visible
00229   addTopLevelItem(item);
00230   scrollToItem(item, QAbstractItemView::EnsureVisible);
00231 }
00232 
00233 QPixmap
00234 StatusEventWidget::addBadgeToPixmap(const QPixmap &pixmap,
00235                                     const QPixmap &badge)
00236 {
00237   QPixmap out = pixmap;
00238   QPainter painter(&out);
00239   painter.drawPixmap(pixmap.width() - badge.width(),
00240                      pixmap.height() - badge.height(),
00241                      badge);
00242   return out;
00243 }
00244 
00245 QPixmap
00246 StatusEventWidget::addBadgeToPixmap(const QPixmap &pixmap,
00247                                     const QString &badge)
00248 {
00249   return StatusEventWidget::addBadgeToPixmap(pixmap, QPixmap(badge));
00250 }
00251 
00252 QPixmap
00253 StatusEventWidget::addBadgeToPixmap(const QString &pixmap,
00254                                     const QString &badge)
00255 {
00256   return StatusEventWidget::addBadgeToPixmap(QPixmap(pixmap), QPixmap(badge));
00257 }
00258 
00259 void
00260 StatusEventWidget::authenticated()
00261 {
00262   TorControl *tc = Vidalia::torControl();
00263 
00264   QString version = tc->getTorVersionString();
00265   QPixmap icon = addBadgeToPixmap(":/images/48x48/tor-logo.png",
00266                                   ":/images/32x32/dialog-ok-apply.png");
00267   addNotification(icon,
00268     tr("The Tor Software is Running"),
00269     tr("You are currently running version \"%1\" of the Tor software.")
00270                                                             .arg(version));
00271 
00272   // Check if Tor established a circuit before we were able to authenticate,
00273   // in which case we missed the CIRCUIT_ESTABLISHED event. So fake it.
00274   if (tc->isCircuitEstablished())
00275     circuitEstablished();
00276 
00277   // Check on the status of Tor's version, in case we missed that event too
00278   QString status = tc->getInfo("status/version/current").toString();
00279   if (! status.compare("old", Qt::CaseInsensitive)
00280         || ! status.compare("obsolete", Qt::CaseInsensitive)) {
00281     dangerousTorVersion(tc::ObsoleteTorVersion, version, QStringList());
00282   } else if (! status.compare("unrecommended", Qt::CaseInsensitive)) {
00283     dangerousTorVersion(tc::UnrecommendedTorVersion, version, QStringList());
00284   }
00285 }
00286 
00287 void
00288 StatusEventWidget::disconnected()
00289 {
00290   QPixmap icon = addBadgeToPixmap(":/images/48x48/tor-logo.png",
00291                                   ":/images/32x32/edit-delete.png");
00292 
00293   addNotification(icon,
00294     tr("The Tor Software is not Running"),
00295     tr("Click \"Start Tor\" in the Vidalia Control Panel to restart the Tor "
00296        "software. If Tor exited unexpectedly, select the \"Advanced\" tab "
00297        "above for details about any errors encountered."));
00298 
00299   _squelchDescriptorAcceptedEvent = false;
00300 }
00301 
00302 void
00303 StatusEventWidget::dangerousTorVersion(tc::TorVersionStatus reason,
00304                                        const QString &version,
00305                                        const QStringList &recommended)
00306 {
00307   Q_UNUSED(recommended);
00308   QString description;
00309   QPixmap icon;
00310 
00311   if (reason == tc::UnrecommendedTorVersion) {
00312     icon = addBadgeToPixmap(":/images/48x48/tor-logo.png",
00313                             ":/images/32x32/security-medium.png");
00314 
00315     description =
00316       tr("You are currently running version \"%1\" of the Tor software, which "
00317          "is no longer recommended. Please upgrade to the most recent version "
00318          "of the software, which may contain important security, reliability "
00319          "and performance fixes.").arg(version);
00320   } else if (reason == tc::ObsoleteTorVersion) {
00321     icon = addBadgeToPixmap(":/images/48x48/tor-logo.png",
00322                             ":/images/32x32/security-low.png");
00323 
00324     description =
00325       tr("You are currently running version \"%1\" of the Tor software, which "
00326          "may no longer work with the current Tor network. Please upgrade "
00327          "to the most recent version of the software, which may contain "
00328          "important security, reliability and performance fixes.").arg(version);
00329   }
00330 
00331   addNotification(icon, tr("Your Tor Software is Out-of-date"), description);
00332 }
00333 
00334 void
00335 StatusEventWidget::circuitEstablished()
00336 {
00337   addNotification(QPixmap(":/images/48x48/network-connect.png"),
00338     tr("Connected to the Tor Network"),
00339     tr("We were able to successfully establish a connection to the Tor "
00340        "network. You can now configure your applications to use the Internet "
00341        "anonymously."));
00342 }
00343 
00344 void
00345 StatusEventWidget::bug(const QString &description)
00346 {
00347   QPixmap icon = addBadgeToPixmap(":/images/48x48/tor-logo.png",
00348                                   ":/images/32x32/script-error.png");
00349   addNotification(icon,
00350     tr("Tor Software Error"),
00351     tr("The Tor software encountered an internal bug. Please report the "
00352        "following error message to the Tor developers at bugs.torproject.org: "
00353        "\"%1\"").arg(description));
00354 }
00355 
00356 void
00357 StatusEventWidget::clockSkewed(int skew, const QString &source)
00358 {
00359   if (source.startsWith("OR:", Qt::CaseInsensitive)) {
00360     // Tor versions 0.2.1.19 and earlier, and 0.2.2.1 and earlier, throw
00361     // this message a little too liberally in this case.
00362     quint32 torVersion = Vidalia::torControl()->getTorVersion();
00363     if (torVersion <= 0x00020113)
00364       return;
00365     QString str = Vidalia::torControl()->getTorVersionString();
00366     if (str.startsWith("0.2.2.") && torVersion <= 0x00020201)
00367       return;
00368   }
00369 
00370   QString description;
00371   QPixmap icon = addBadgeToPixmap(":/images/48x48/chronometer.png",
00372                                   ":/images/32x32/dialog-warning.png");
00373 
00374   if (skew < 0) {
00375     description =
00376       tr("Tor has determined that your computer's clock may be set to %1 "
00377          "seconds in the past compared to the source \"%2\". If your "
00378          "clock is not correct, Tor will not be able to function. Please "
00379          "verify your computer displays the correct time.").arg(qAbs(skew))
00380                                                            .arg(source);
00381   } else {
00382     description =
00383       tr("Tor has determined that your computer's clock may be set to %1 "
00384          "seconds in the future compared to the source \"%2\". If "
00385          "your clock is not correct, Tor will not be able to function. Please "
00386          "verify your computer displays the correct time.").arg(qAbs(skew))
00387                                                            .arg(source);
00388   }
00389   addNotification(icon, tr("Your Computer's Clock is Potentially Incorrect"),
00390                   description);
00391 }
00392 
00393 void
00394 StatusEventWidget::dangerousPort(quint16 port, bool rejected)
00395 {
00396   QPixmap icon;
00397   QString description;
00398 
00399   if (rejected) {
00400     icon = addBadgeToPixmap(":/images/48x48/applications-internet.png",
00401                             ":/images/32x32/security-low.png");
00402 
00403     description =
00404       tr("One of the applications on your computer may have attempted to "
00405          "make an unencrypted connection through Tor to port %1. Sending "
00406          "unencrypted information over the Tor network is dangerous and not "
00407          "recommended. For your protection, Tor has automatically closed this "
00408          "connection.").arg(port);
00409   } else {
00410     icon = addBadgeToPixmap(":/images/48x48/applications-internet.png",
00411                             ":/images/32x32/security-medium.png");
00412     description =
00413       tr("One of the applications on your computer may have attempted to "
00414          "make an unencrypted connection through Tor to port %1. Sending "
00415          "unencrypted information over the Tor network is dangerous and not "
00416          "recommended.").arg(port);
00417   }
00418 
00419   addNotification(icon, tr("Potentially Dangerous Connection!"), description);
00420 }
00421 
00422 void
00423 StatusEventWidget::socksError(tc::SocksError type, const QString &destination)
00424 {
00425   QString title, description;
00426   QPixmap icon = QPixmap(":/images/48x48/applications-internet.png");
00427 
00428   if (type == tc::DangerousSocksTypeError) {
00429     icon  = addBadgeToPixmap(icon, ":/images/32x32/security-medium.png");
00430 
00431     title = tr("Potentially Dangerous Connection!");
00432     description =
00433       tr("One of your applications established a connection through Tor "
00434          "to \"%1\" using a protocol that may leak information about your "
00435          "destination. Please ensure you configure your applications to use "
00436          "only SOCKS4a or SOCKS5 with remote hostname resolution.")
00437                                                             .arg(destination);
00438   } else if (type == tc::UnknownSocksProtocolError) {
00439     icon = addBadgeToPixmap(icon, ":/images/32x32/dialog-warning.png");
00440 
00441     title = tr("Unknown SOCKS Protocol");
00442     description =
00443       tr("One of your applications tried to establish a connection through "
00444          "Tor using a protocol that Tor does not understand. Please ensure "
00445          "you configure your applications to use only SOCKS4a or SOCKS5 with "
00446          "remote hostname resolution.");
00447   } else if (type == tc::BadSocksHostnameError) {
00448     icon = addBadgeToPixmap(icon, ":/images/32x32/dialog-warning.png");
00449 
00450     title = tr("Invalid Destination Hostname");
00451     description =
00452       tr("One of your applications tried to establish a connection through "
00453          "Tor to \"%1\", which Tor does not recognize as a valid hostname. "
00454          "Please check your application's configuration.").arg(destination);
00455   } else {
00456     return;
00457   }
00458 
00459   addNotification(icon, title, description);
00460 }
00461 
00462 void
00463 StatusEventWidget::externalAddressChanged(const QHostAddress &ip,
00464                                           const QString &hostname)
00465 {
00466   QString hostString = hostname.isEmpty() ? QString()
00467                                           : QString(" (%1)").arg(hostname);
00468 
00469   addNotification(QPixmap(":/images/48x48/applications-internet.png"),
00470     tr("External IP Address Changed"),
00471     tr("Tor has determined your relay's public IP address is currently %1%2. "
00472        "If that is not correct, please consider setting the 'Address' option "
00473        "in your relay's configuration.").arg(ip.toString()).arg(hostString));
00474 }
00475 
00476 void
00477 StatusEventWidget::dnsHijacked()
00478 {
00479   QPixmap icon = addBadgeToPixmap(":/images/48x48/applications-internet.png",
00480                                   ":/images/32x32/dialog-warning.png");
00481   addNotification(icon,
00482     tr("DNS Hijacking Detected"),
00483     tr("Tor detected that your DNS provider is providing false responses for "
00484        "domains that do not exist. Some ISPs and other DNS providers, such as "
00485        "OpenDNS, are known to do this in order to display their own search or "
00486        "advertising pages."));
00487 }
00488 
00489 void
00490 StatusEventWidget::dnsUseless()
00491 {
00492   QPixmap icon = addBadgeToPixmap(":/images/48x48/applications-internet.png",
00493                                   ":/images/32x32/edit-delete.png");
00494   addNotification(icon,
00495     tr("DNS Hijacking Detected"),
00496     tr("Tor detected that your DNS provider is providing false responses for "
00497        "well known domains. Since clients rely on Tor network relays to "
00498        "provide accurate DNS repsonses, your relay will not be configured as "
00499        "an exit relay."));
00500 }
00501 
00502 void
00503 StatusEventWidget::checkingOrPortReachability(const QHostAddress &ip,
00504                                               quint16 port)
00505 {
00506   addNotification(QPixmap(":/images/48x48/network-wired.png"),
00507     tr("Checking Server Port Reachability"),
00508     tr("Tor is trying to determine if your relay's server port is reachable "
00509        "from the Tor network by connecting to itself at %1:%2. This test "
00510        "could take several minutes.").arg(ip.toString()).arg(port));
00511 }
00512 
00513 void
00514 StatusEventWidget::orPortReachabilityFinished(const QHostAddress &ip,
00515                                               quint16 port,
00516                                               bool reachable)
00517 {
00518   QString title, description;
00519   QPixmap icon = QPixmap(":/images/48x48/network-wired.png");
00520   if (reachable) {
00521     icon = addBadgeToPixmap(icon, ":/images/32x32/dialog-ok-apply.png");
00522     title = tr("Server Port Reachability Test Successful!");
00523     description =
00524       tr("Your relay's server port is reachable from the Tor network!");
00525   } else {
00526     icon = addBadgeToPixmap(icon, ":/images/32x32/dialog-warning.png");
00527     title = tr("Server Port Reachability Test Failed");
00528     description =
00529       tr("Your relay's server port is not reachable by other Tor clients. This "
00530          "can happen if you are behind a router or firewall that requires you "
00531          "to set up port forwarding. If %1:%2 is not your correct IP address "
00532          "and server port, please check your relay's configuration.")
00533                                                 .arg(ip.toString()).arg(port);
00534   }
00535 
00536   addNotification(icon, title, description);
00537 }
00538 
00539 void
00540 StatusEventWidget::checkingDirPortReachability(const QHostAddress &ip,
00541                                                quint16 port)
00542 {
00543   addNotification(QPixmap(":/images/48x48/network-wired.png"),
00544     tr("Checking Directory Port Reachability"),
00545     tr("Tor is trying to determine if your relay's directory port is reachable "
00546        "from the Tor network by connecting to itself at %1:%2. This test "
00547        "could take several minutes.").arg(ip.toString()).arg(port));
00548 }
00549 
00550 void
00551 StatusEventWidget::dirPortReachabilityFinished(const QHostAddress &ip,
00552                                                quint16 port,
00553                                                bool reachable)
00554 {
00555   QString title, description;
00556   QPixmap icon = QPixmap(":/images/48x48/network-wired.png");
00557   if (reachable) {
00558     icon = addBadgeToPixmap(icon, ":/images/32x32/dialog-ok-apply.png");
00559     title = tr("Directory Port Reachability Test Successful!");
00560     description =
00561       tr("Your relay's directory port is reachable from the Tor network!");
00562   } else {
00563     icon = addBadgeToPixmap(icon, ":/images/32x32/dialog-warning.png");
00564     title = tr("Directory Port Reachability Test Failed");
00565     description =
00566       tr("Your relay's directory port is not reachable by other Tor clients. "
00567          "This can happen if you are behind a router or firewall that requires "
00568          "you to set up port forwarding. If %1:%2 is not your correct IP "
00569          "address and directory port, please check your relay's configuration.")
00570                                                 .arg(ip.toString()).arg(port);
00571   }
00572 
00573   addNotification(icon, title, description);
00574 }
00575 
00576 void
00577 StatusEventWidget::serverDescriptorRejected(const QHostAddress &ip,
00578                                             quint16 port,
00579                                             const QString &reason)
00580 {
00581   QPixmap icon =
00582     addBadgeToPixmap(":/images/48x48/preferences-system-network-sharing.png",
00583                      ":/images/32x32/dialog-warning.png");
00584 
00585   addNotification(icon,
00586     tr("Relay Descriptor Rejected"),
00587     tr("Your relay's descriptor, which enables clients to connect to your "
00588        "relay, was rejected by the directory server at %1:%2. The reason "
00589        "given was: %3").arg(ip.toString()).arg(port).arg(reason));
00590 }
00591 
00592 void
00593 StatusEventWidget::serverDescriptorAccepted(const QHostAddress &ip,
00594                                             quint16 port)
00595 {
00596   Q_UNUSED(ip);
00597   Q_UNUSED(port);
00598 
00599   if (_squelchDescriptorAcceptedEvent)
00600     return;
00601    _squelchDescriptorAcceptedEvent = true;
00602 
00603   QPixmap icon =
00604     addBadgeToPixmap(":/images/48x48/preferences-system-network-sharing.png",
00605                      ":/images/32x32/dialog-ok-apply.png");
00606 
00607   addNotification(icon,
00608     tr("Your Relay is Online"),
00609     tr("Your relay is now online and available for Tor clients to use. You "
00610        "should see an increase in network traffic shown by the Bandwidth "
00611        "Graph within a few hours as more clients learn about your relay. "
00612        "Thank you for contributing to the Tor network!"));
00613 }
00614 

Generated on 31 Mar 2010 for Vidalia by  doxygen 1.6.1