networkpage.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 networkpage.cpp
00013 ** \version $Id: networkpage.cpp 2403 2008-03-13 04:34:19Z edmanm $
00014 ** \brief Network and firewall configuration options
00015 */
00016 
00017 #include <QMenu>
00018 #include <QIntValidator>
00019 #include <QClipboard>
00020 #include <QHostAddress>
00021 #include <networksettings.h>
00022 #include <vmessagebox.h>
00023 #include <vidalia.h>
00024 #include <stringutil.h>
00025 
00026 #include "networkpage.h"
00027 #include "domainvalidator.h"
00028 
00029 #define IMG_COPY  ":/images/22x22/edit-copy.png"
00030 
00031 
00032 /** Constructor */
00033 NetworkPage::NetworkPage(QWidget *parent)
00034 : ConfigPage(parent, tr("Network"))
00035 {
00036   /* Invoke the Qt Designer generated object setup routine */
00037   ui.setupUi(this);
00038  
00039   connect(ui.btnAddBridge, SIGNAL(clicked()), this, SLOT(addBridge()));
00040   connect(ui.btnRemoveBridge, SIGNAL(clicked()), this, SLOT(removeBridge()));
00041   connect(ui.btnCopyBridge, SIGNAL(clicked()), 
00042           this, SLOT(copySelectedBridgesToClipboard()));
00043   connect(ui.listBridges, SIGNAL(customContextMenuRequested(QPoint)),
00044           this, SLOT(bridgeContextMenuRequested(QPoint)));
00045   connect(ui.listBridges, SIGNAL(itemSelectionChanged()),
00046           this, SLOT(bridgeSelectionChanged()));
00047   connect(ui.lineBridge, SIGNAL(returnPressed()), this, SLOT(addBridge()));
00048   connect(Vidalia::torControl(), SIGNAL(authenticated()),
00049           this, SLOT(onAuthenticated()));
00050   connect(Vidalia::torControl(), SIGNAL(disconnected()),
00051           this, SLOT(onDisconnected()));
00052   connect(ui.lblHelpFindBridges, SIGNAL(linkActivated(QString)),
00053           this, SLOT(onLinkActivated(QString)));
00054           
00055   ui.lblNoBridgeSupport->setVisible(false);
00056   ui.lineHttpProxyAddress->setValidator(new DomainValidator(this));
00057   ui.lineHttpProxyPort->setValidator(new QIntValidator(1, 65535, this));
00058 
00059   vApp->createShortcut(QKeySequence(QKeySequence::Copy),
00060                        ui.listBridges, this,
00061                        SLOT(copySelectedBridgesToClipboard()));
00062 
00063 #if defined(Q_WS_MAC)
00064   /* On OS X, the network page looks better without frame titles. Everywhere
00065    * else needs titles or else there's a break in the frame border. */
00066   ui.grpProxySettings->setTitle("");
00067   ui.grpFirewallSettings->setTitle("");
00068   ui.grpBridgeSettings->setTitle("");
00069 #endif
00070 }
00071 
00072 /** Applies the network configuration settings to Tor. Returns true if the   *
00073  * settings were applied successfully. Otherwise, <b>errmsg</b> is set and   *
00074  * false is returned. */
00075 bool
00076 NetworkPage::apply(QString &errmsg)
00077 {
00078   return NetworkSettings(Vidalia::torControl()).apply(&errmsg);
00079 }
00080 
00081 /** Returns true if the user has changed their server settings since the   *
00082  * last time they were applied to Tor. */
00083 bool
00084 NetworkPage::changedSinceLastApply()
00085 {
00086   return NetworkSettings(Vidalia::torControl()).changedSinceLastApply();
00087 }
00088 
00089 /** Reverts the server configuration settings to their values at the last   *
00090  * time they were successfully applied to Tor. */
00091 void
00092 NetworkPage::revert()
00093 {
00094   NetworkSettings settings(Vidalia::torControl());
00095   settings.revert();
00096 }
00097 
00098 /** Called when Vidalia has connected and authenticated to Tor. This will
00099  * check Tor's version number and, if it's too old, will disable the bridge
00100  * settings UI and show a message indicating the user's Tor is too old. */
00101 void
00102 NetworkPage::onAuthenticated()
00103 {
00104   quint32 torVersion = Vidalia::torControl()->getTorVersion();
00105   if (torVersion < 0x020003) {
00106     ui.grpBridgeSettings->setEnabled(false);
00107     ui.lblNoBridgeSupport->setVisible(true);
00108   }
00109 }
00110 
00111 /** Called when Vidalia disconnects from Tor. This will reenable the bridge
00112  * settings (if they were previously disabled) and hide the warning message
00113  * indicating the user's Tor does not support bridges. */
00114 void
00115 NetworkPage::onDisconnected()
00116 {
00117   ui.grpBridgeSettings->setEnabled(true);
00118   ui.lblNoBridgeSupport->setVisible(false);
00119 }
00120 
00121 /** Called when a link in a label is clicked. <b>url</b> is the target of
00122  * the clicked link. */
00123 void
00124 NetworkPage::onLinkActivated(const QString &url)
00125 {
00126   emit helpRequested(url);
00127 }
00128 
00129 /** Verifies that <b>bridge</b> is a valid bridge identifier and places a 
00130  * normalized identifier in <b>out</b>. The normalized identifier will have
00131  * all spaces removed from the fingerprint portion (if any) and all
00132  * hexadecimal characters converted to uppercase. Returns true if
00133  * <b>bridge</b> is a valid bridge identifier, false otherwise. */
00134 bool
00135 NetworkPage::validateBridge(const QString &bridge, QString *out)
00136 {
00137   QString temp = bridge;
00138   if (temp.startsWith("bridge ", Qt::CaseInsensitive))
00139     temp = temp.remove(0, 7); /* remove "bridge " */
00140 
00141   QStringList parts = temp.split(" ", QString::SkipEmptyParts);
00142   if (parts.isEmpty())
00143     return false;
00144 
00145   QString s = parts.at(0);
00146   if (s.contains(":")) {
00147     if (s.endsWith(":"))
00148       return false;
00149 
00150     int index = s.indexOf(":");
00151     QString host = s.mid(0, index);
00152     QString port = s.mid(index + 1);
00153     if (QHostAddress(host).isNull()
00154           || QHostAddress(host).protocol() != QAbstractSocket::IPv4Protocol
00155           || port.toUInt() < 1 
00156           || port.toUInt() > 65535)
00157       return false;
00158     temp = s;
00159     if (parts.size() > 1) {
00160       QString fp = static_cast<QStringList>(parts.mid(1)).join("");
00161       if (fp.length() != 40 || !string_is_hex(fp))
00162         return false;
00163       temp += " " + fp.toUpper();
00164     }
00165   } else {
00166     QString fp = parts.join("");
00167     if (fp.length() != 40 || !string_is_hex(fp))
00168       return false;
00169     temp = fp.toUpper();
00170   }
00171   *out = temp;
00172   return true;
00173 }
00174 
00175 /** Adds a bridge to the bridge list box. */
00176 void
00177 NetworkPage::addBridge()
00178 {
00179   QString bridge;
00180   QString input = ui.lineBridge->text().trimmed();
00181 
00182   if (input.isEmpty())
00183     return;
00184   if (!validateBridge(input, &bridge)) {
00185     VMessageBox::warning(this,
00186                   tr("Invalid Bridge"),
00187                   tr("The specified bridge identifier is not valid."),
00188                   VMessageBox::Ok|VMessageBox::Default);
00189     return;
00190   }
00191   if (!ui.listBridges->findItems(bridge, Qt::MatchFixedString).isEmpty())
00192     return; /* duplicate bridge */
00193 
00194   ui.listBridges->addItem(bridge);
00195   ui.lineBridge->clear();
00196 }
00197 
00198 /** Removes one or more selected bridges from the bridge list box. */
00199 void
00200 NetworkPage::removeBridge()
00201 {
00202   qDeleteAll(ui.listBridges->selectedItems());
00203 }
00204 
00205 /** Copies all selected bridges to the clipboard. */
00206 void
00207 NetworkPage::copySelectedBridgesToClipboard()
00208 {
00209   QString contents;
00210 
00211   foreach (QListWidgetItem *item, ui.listBridges->selectedItems()) {
00212 #if defined(Q_WS_WIN)
00213     contents += item->text() + "\r\n";
00214 #else
00215     contents += item->text() + "\n";
00216 #endif
00217   }
00218   if (!contents.isEmpty())
00219     vApp->clipboard()->setText(contents.trimmed());
00220 }
00221 
00222 /** Called when the user right-clicks on a bridge and displays a context
00223  * menu. */
00224 void
00225 NetworkPage::bridgeContextMenuRequested(const QPoint &pos)
00226 {
00227   QMenu menu(this);
00228   
00229   QListWidgetItem *item = ui.listBridges->itemAt(pos);
00230   if (!item)
00231     return;
00232   
00233   QAction *copyAction =
00234     new QAction(QIcon(IMG_COPY), tr("Copy (Ctrl+C)"), &menu);
00235   connect(copyAction, SIGNAL(triggered()),
00236           this, SLOT(copySelectedBridgesToClipboard()));
00237 
00238   menu.addAction(copyAction);
00239   menu.exec(ui.listBridges->mapToGlobal(pos));
00240 }
00241 
00242 /** Called when the user changes which bridges they have selected. */
00243 void
00244 NetworkPage::bridgeSelectionChanged()
00245 {
00246   bool enabled = !ui.listBridges->selectedItems().isEmpty();
00247   ui.btnCopyBridge->setEnabled(enabled);
00248   ui.btnRemoveBridge->setEnabled(enabled);
00249 }
00250 
00251 /** Saves changes made to settings on the Firewall settings page. */
00252 bool
00253 NetworkPage::save(QString &errmsg)
00254 {
00255   NetworkSettings settings(Vidalia::torControl());
00256   QStringList bridgeList;
00257   QList<quint16> reachablePorts;
00258   bool ok;
00259   
00260   if (ui.chkUseProxy->isChecked()
00261         && (ui.lineHttpProxyAddress->text().isEmpty()
00262             || ui.lineHttpProxyPort->text().isEmpty())) {
00263     errmsg = tr("You must specify both an IP address or hostname and a "
00264                 "port number to configure Tor to use a proxy to access "
00265                 "the Internet.");
00266     return false;
00267   }
00268   if (ui.chkFascistFirewall->isChecked()
00269         && ui.lineReachablePorts->text().isEmpty()) {
00270     errmsg = tr("You must specify one or more ports to which your "
00271                 "firewall allows you to connect.");
00272     return false;
00273   }
00274 
00275   /* Save the HTTP/HTTPS proxy settings */
00276   settings.setUseHttpProxy(ui.chkUseProxy->isChecked());
00277   settings.setUseHttpsProxy(ui.chkProxyUseHttps->isChecked());
00278   if (!ui.lineHttpProxyAddress->text().isEmpty()) {
00279     QString proxy = ui.lineHttpProxyAddress->text();
00280     if (!ui.lineHttpProxyPort->text().isEmpty())
00281       proxy += ":" + ui.lineHttpProxyPort->text();
00282 
00283     settings.setHttpProxy(proxy);
00284     settings.setHttpsProxy(proxy);
00285   } else {
00286     settings.setHttpProxy("");
00287     settings.setHttpsProxy("");
00288   }
00289 
00290   if (!ui.lineHttpProxyUsername->text().isEmpty() ||
00291       !ui.lineHttpProxyPassword->text().isEmpty()) {
00292     QString auth = ui.lineHttpProxyUsername->text() + ":" +
00293                    ui.lineHttpProxyPassword->text();
00294     settings.setHttpProxyAuthenticator(auth);
00295     settings.setHttpsProxyAuthenticator(auth);
00296   } else {
00297     settings.setHttpProxyAuthenticator("");
00298     settings.setHttpsProxyAuthenticator("");
00299   }
00300   
00301   /* Save the reachable port settings */
00302   settings.setFascistFirewall(ui.chkFascistFirewall->isChecked());
00303   foreach (QString portString,
00304            ui.lineReachablePorts->text().split(",", QString::SkipEmptyParts)) {
00305     quint32 port = portString.toUInt(&ok);
00306     if (!ok || port < 1 || port > 65535) {
00307       errmsg = tr("'%1' is not a valid port number.").arg(portString);
00308       return false;
00309     }
00310     reachablePorts << (quint16)port;
00311   }
00312   settings.setReachablePorts(reachablePorts);
00313 
00314   /* Save the bridge settings */
00315   settings.setUseBridges(ui.chkUseBridges->isChecked());
00316   for (int i = 0; i < ui.listBridges->count(); i++)
00317     bridgeList << ui.listBridges->item(i)->text();
00318   settings.setBridgeList(bridgeList);
00319 
00320   return true;
00321 }
00322 
00323 /** Loads previously saved settings */
00324 void
00325 NetworkPage::load()
00326 {
00327   NetworkSettings settings(Vidalia::torControl());
00328   QStringList reachablePortStrings;
00329 
00330   /* Load HTTP/HTTPS proxy settings */
00331   ui.chkUseProxy->setChecked(settings.getUseHttpProxy());
00332   ui.chkProxyUseHttps->setChecked(settings.getUseHttpsProxy());
00333   QStringList proxy = settings.getHttpProxy().split(":");
00334   QStringList proxyAuth = settings.getHttpProxyAuthenticator().split(":");
00335   if (proxy.size() >= 1)
00336     ui.lineHttpProxyAddress->setText(proxy.at(0));
00337   if (proxy.size() >= 2)
00338     ui.lineHttpProxyPort->setText(proxy.at(1));
00339   if (proxyAuth.size() >= 1)  
00340     ui.lineHttpProxyUsername->setText(proxyAuth.at(0));
00341   if (proxyAuth.size() >= 2)
00342     ui.lineHttpProxyPassword->setText(proxyAuth.at(1));
00343 
00344   /* Load firewall settings */
00345   ui.chkFascistFirewall->setChecked(settings.getFascistFirewall());
00346   QList<quint16> reachablePorts = settings.getReachablePorts();
00347   foreach (quint16 port, reachablePorts) {
00348     reachablePortStrings << QString::number(port);
00349   }
00350   ui.lineReachablePorts->setText(reachablePortStrings.join(","));
00351 
00352   /* Load bridge settings */
00353   ui.chkUseBridges->setChecked(settings.getUseBridges()); 
00354   ui.listBridges->clear();
00355   ui.listBridges->addItems(settings.getBridgeList());
00356 }
00357 

Generated on Tue Jul 7 16:58:26 2009 for Vidalia by  doxygen 1.4.7