serverpage.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 serverpage.cpp
00013 ** \version $Id: serverpage.cpp 2685 2008-06-10 05:22:58Z edmanm $
00014 ** \brief Tor server configuration options
00015 */
00016 
00017 #include <QClipboard>
00018 #include <vidalia.h>
00019 #include <vmessagebox.h>
00020 #include <html.h>
00021 #include <config.h>
00022 
00023 #include "configdialog.h"
00024 #include "serverpage.h"
00025 #include "ipvalidator.h"
00026 #include "portvalidator.h"
00027 #include "domainvalidator.h"
00028 #include "nicknamevalidator.h"
00029 
00030 #if defined(USE_MINIUPNPC)
00031 #include "upnptestdialog.h"
00032 #endif
00033 
00034 /* These are completely made up values (in bytes/sec). */
00035 #define CABLE256_AVG_RATE       (32*1024)
00036 #define CABLE256_MAX_RATE       (64*1024)
00037 #define CABLE512_AVG_RATE       (64*1024)
00038 #define CABLE512_MAX_RATE       (128*1024)
00039 #define CABLE768_AVG_RATE       (96*1024)
00040 #define CABLE768_MAX_RATE       (192*1024)
00041 #define T1_AVG_RATE             (192*1024)
00042 #define T1_MAX_RATE             (384*1024)
00043 #define HIGHBW_AVG_RATE         (5120*1024)
00044 #define HIGHBW_MAX_RATE         (10240*1024)
00045 /** Minimum allowed bandwidth rate (20KB) */
00046 #define MIN_BANDWIDTH_RATE      20
00047 /** Maximum bandwidth rate. This is limited to 2147483646 bytes, 
00048  * or 2097151 kilobytes. (2147483646/1024) */ 
00049 #define MAX_BANDWIDTH_RATE      2097151
00050 
00051 /** Ports represented by the "Websites" checkbox. (80) */
00052 #define PORTS_HTTP   (QStringList() << "80")
00053 /** Ports represented by the "Secure Websites" checkbox. (443) */
00054 #define PORTS_HTTPS  (QStringList() << "443")
00055 /** Ports represented by the "Retrieve Mail" checkbox. (110,143,993,995) */
00056 #define PORTS_MAIL   (QStringList() << "110" << "143" << "993" << "995")
00057 /** Ports represented by the "Instant Messaging" checkbox.
00058  * (703,1863,5050,5190,5222,8300,8888) */
00059 #define PORTS_IM     (QStringList() << "706" << "1863" << "5050" << "5190" \
00060                                     << "5222" << "5223" << "8300" << "8888")
00061 /** Ports represented by the "Internet Relay Chat" checkbox. 
00062  * (6660-6669,6697) */
00063 #define PORTS_IRC    (QStringList() << "6660-6669" << "6697")
00064 
00065 
00066 /** Constructor */
00067 ServerPage::ServerPage(QWidget *parent)
00068 : ConfigPage(parent, tr("Server"))
00069 {
00070   /* Invoke the Qt Designer generated object setup routine */
00071   ui.setupUi(this);
00072   
00073   /* Create ServerSettings object */
00074   _settings = new ServerSettings(Vidalia::torControl());
00075 
00076   /* Bind events to actions */
00077   connect(ui.btnRateHelp, SIGNAL(clicked()), this, SLOT(bandwidthHelp()));
00078   connect(ui.btnExitHelp, SIGNAL(clicked()), this, SLOT(exitPolicyHelp()));
00079   connect(ui.btnUpnpHelp, SIGNAL(clicked()), this, SLOT(upnpHelp()));
00080   connect(ui.cmboRate, SIGNAL(currentIndexChanged(int)),
00081                  this, SLOT(rateChanged(int)));
00082   connect(ui.lineAvgRateLimit, SIGNAL(editingFinished()), 
00083                          this, SLOT(customRateChanged()));
00084   connect(ui.lineMaxRateLimit, SIGNAL(editingFinished()), 
00085                          this, SLOT(customRateChanged()));
00086   connect(ui.rdoClientMode, SIGNAL(toggled(bool)),
00087                       this, SLOT(serverModeChanged(bool)));
00088   connect(ui.rdoServerMode, SIGNAL(toggled(bool)),
00089                       this, SLOT(serverModeChanged(bool)));
00090   connect(ui.rdoBridgeMode, SIGNAL(toggled(bool)),
00091                       this, SLOT(serverModeChanged(bool)));
00092   connect(Vidalia::torControl(), SIGNAL(authenticated()),
00093                            this, SLOT(onAuthenticated()));
00094   connect(Vidalia::torControl(), SIGNAL(disconnected()),
00095                            this, SLOT(onDisconnected()));
00096   connect(ui.btnCopyBridgeIdentity, SIGNAL(clicked()),
00097                               this, SLOT(copyBridgeIdentity()));
00098 
00099   /* Set validators for address, mask and various port number fields */
00100   ui.lineServerNickname->setValidator(new NicknameValidator(this));
00101   ui.lineServerPort->setValidator(new QIntValidator(1, 65535, this));
00102   ui.lineDirPort->setValidator(new QIntValidator(1, 65535, this));
00103   ui.lineAvgRateLimit->setValidator(
00104     new QIntValidator(MIN_BANDWIDTH_RATE, MAX_BANDWIDTH_RATE, this));
00105   ui.lineMaxRateLimit->setValidator(
00106     new QIntValidator(MIN_BANDWIDTH_RATE, MAX_BANDWIDTH_RATE, this));
00107 
00108 #if defined(USE_MINIUPNPC)
00109   connect(ui.btnTestUpnp, SIGNAL(clicked()), this, SLOT(testUpnp()));
00110 #else
00111   ui.chkEnableUpnp->setVisible(false);
00112   ui.btnTestUpnp->setVisible(false);
00113 #endif
00114 }
00115 
00116 /** Destructor */
00117 ServerPage::~ServerPage()
00118 {
00119   delete _settings;
00120 }
00121 
00122 /** Called when Vidalia has authenticated to Tor. If the user's Tor is not
00123  * recent enough, this disables the bridge server option and displays a
00124  * warning if the user had previously configured Tor as a bridge. */
00125 void
00126 ServerPage::onAuthenticated()
00127 {
00128   quint32 torVersion = Vidalia::torControl()->getTorVersion();
00129   if (torVersion < 0x020008) {
00130     ui.rdoBridgeMode->setEnabled(false);
00131     if (ui.rdoBridgeMode->isChecked()) {
00132       int ret = VMessageBox::warning(this,
00133                   tr("Bridge Support Unavailable"),
00134                   p(tr("You have configured Tor to act as a bridge relay "
00135                        "for censored users, but your version of Tor does not "
00136                        "support bridges.")) +
00137                   p(tr("Please upgrade your Tor software or configure Tor to "
00138                        "act as a normal Tor relay.")),
00139                   VMessageBox::ShowSettings|VMessageBox::Default,
00140                   VMessageBox::Cancel);
00141       if (ret == VMessageBox::ShowSettings) {
00142         ConfigDialog *dialog = dynamic_cast<ConfigDialog *>(window());
00143         if (dialog)
00144           dialog->showWindow(ConfigDialog::Server);
00145       }
00146     }
00147   }
00148 }
00149 
00150 /** Called when Vidalia disconnects from Tor. This method reenables the bridge
00151  * server option. */
00152 void
00153 ServerPage::onDisconnected()
00154 {
00155   ui.rdoBridgeMode->setEnabled(true);
00156 }
00157 
00158 /** Copies the user's bridge relay identity to the clipboard. */
00159 void
00160 ServerPage::copyBridgeIdentity()
00161 {
00162   QString bridge = ui.lblBridgeIdentity->text();
00163   if (!bridge.isEmpty())
00164     vApp->clipboard()->setText(bridge);
00165 }
00166 
00167 /** Loads the user's bridge relay identity into the appropriate widgets. If
00168  * the user's bridge is not running, then "Not Running" will be displayed.
00169  * Otherwise, either the bridge's "address:port", "fingerprint", or
00170  * "address:port fingerprint" will be displayed, depending on whether our
00171  * GETCONF and GETINFO commands are successful. */
00172 void
00173 ServerPage::loadBridgeIdentity()
00174 {
00175   TorControl *tc = Vidalia::torControl();
00176   QString bridge, address, orPort, fingerprint;
00177 
00178   if (tc->isConnected()) {
00179     tc->getInfo("address", address);
00180     tc->getInfo("fingerprint", fingerprint);
00181     tc->getConf("ORPort", orPort);
00182   
00183     if (!address.isEmpty() && !orPort.isEmpty() && orPort != "0")
00184       bridge = address + ":" + orPort + " ";
00185     if (!fingerprint.isEmpty())
00186       bridge += fingerprint;
00187     bridge = bridge.trimmed();
00188   }
00189 
00190   ui.lblBridgeIdentity->setText(bridge.isEmpty()
00191                                   ? tr("Your bridge relay is not running.")
00192                                   : bridge);
00193   ui.lblYourBridgeRelayIs->setEnabled(!bridge.isEmpty());
00194   ui.lblBridgeIdentity->setEnabled(!bridge.isEmpty());
00195   ui.btnCopyBridgeIdentity->setEnabled(!bridge.isEmpty());
00196 }
00197 
00198 /** Called when the user toggles any one of the server mode radio buttons
00199  * and hides or displays the server configuration tabs appropriately. */
00200 void
00201 ServerPage::serverModeChanged(bool enabled)
00202 {
00203   Q_UNUSED(enabled);
00204   bool bridgeEnabled = ui.rdoBridgeMode->isChecked();
00205   
00206   /* Show the tab menu only if the user is running a normal relay or a bridge
00207    * relay. */
00208   ui.tabsMenu->setVisible(ui.rdoServerMode->isChecked() || bridgeEnabled);
00209   
00210   /* Disable the Exit Policies tab when bridge relay mode is selected */
00211   ui.tabsMenu->setTabEnabled(2, !bridgeEnabled);
00212   
00213   /* Display the widgets that show the user their bridge identity if bridge
00214    * relay mode is selected. */
00215   ui.lblYourBridgeRelayIs->setVisible(bridgeEnabled);
00216   ui.lblBridgeIdentity->setVisible(bridgeEnabled);
00217   ui.btnCopyBridgeIdentity->setVisible(bridgeEnabled);
00218 }
00219 
00220 /** Returns true if the user has changed their server settings since the
00221  * last time they were applied to Tor. */
00222 bool
00223 ServerPage::changedSinceLastApply()
00224 {
00225   return _settings->changedSinceLastApply();
00226 }
00227 
00228 /** Applies the server configuration settings to Tor. Returns true if the
00229  * settings were applied successfully. Otherwise, <b>errmsg</b> is
00230  * set and false is returned. */
00231 bool
00232 ServerPage::apply(QString &errmsg)
00233 {
00234   return _settings->apply(&errmsg);
00235 }
00236 
00237 /** Returns true if the user has changed their server settings since the
00238  * last time they were applied to Tor. */
00239 void
00240 ServerPage::revert()
00241 {
00242   _settings->revert();
00243 }
00244 
00245 /** Saves changes made to settings on the Server settings page. */
00246 bool
00247 ServerPage::save(QString &errmsg)
00248 {
00249   /* Force the bandwidth rate limits to validate */
00250   customRateChanged();
00251   
00252   if (ui.rdoServerMode->isChecked() || ui.rdoBridgeMode->isChecked()) {
00253     /* A server must have an ORPort and a nickname */
00254     if (ui.lineServerPort->text().isEmpty() ||
00255         ui.lineServerNickname->text().isEmpty()) {
00256       errmsg = tr("You must specify at least a relay nickname and port.");
00257       return false;
00258     }
00259     /* If the bandwidth rates aren't set, use some defaults before saving */
00260     if (ui.lineAvgRateLimit->text().isEmpty()) {
00261       ui.lineAvgRateLimit->setText(QString::number(2097152/1024) /* 2MB */);
00262     }
00263     if (ui.lineMaxRateLimit->text().isEmpty()) {
00264       ui.lineMaxRateLimit->setText(QString::number(5242880/1024) /* 5MB */);
00265     }
00266   }
00267   
00268   /* "Server" is enabled whether we're a bridge or normal relay. "Bridge" is
00269    * only enabled if we're a bridge (obviously). */
00270   _settings->setServerEnabled(ui.rdoServerMode->isChecked()
00271                                 || ui.rdoBridgeMode->isChecked());
00272   _settings->setBridgeEnabled(ui.rdoBridgeMode->isChecked());
00273   
00274   /* Save the rest of the server settings. */
00275   _settings->setDirectoryMirror(ui.chkMirrorDirectory->isChecked());
00276   _settings->setNickname(ui.lineServerNickname->text());
00277   _settings->setORPort(ui.lineServerPort->text().toUInt());
00278   _settings->setDirPort(ui.lineDirPort->text().toUInt());
00279   _settings->setContactInfo(ui.lineServerContact->text());
00280   saveBandwidthLimits();
00281   saveExitPolicies();
00282 
00283 #if defined(USE_MINIUPNPC)
00284   _settings->setUpnpEnabled(ui.chkEnableUpnp->isChecked());
00285 #endif
00286 
00287   return true;
00288 }
00289 
00290 /** Loads previously saved settings */
00291 void
00292 ServerPage::load()
00293 {
00294   if (_settings->isBridgeEnabled())
00295     ui.rdoBridgeMode->setChecked(true);
00296   else if (_settings->isServerEnabled())
00297     ui.rdoServerMode->setChecked(true);
00298   else
00299     ui.rdoClientMode->setChecked(true);
00300 
00301   ui.lineServerNickname->setText(_settings->getNickname());
00302   ui.lineServerPort->setText(QString::number(_settings->getORPort()));
00303   ui.lineDirPort->setText(QString::number(_settings->getDirPort()));
00304   ui.lineServerContact->setText(_settings->getContactInfo());
00305   ui.chkMirrorDirectory->setChecked(_settings->isDirectoryMirror());
00306   
00307   loadBandwidthLimits();
00308   loadExitPolicies();
00309   loadBridgeIdentity();
00310 
00311 #if defined(USE_MINIUPNPC)
00312   ui.chkEnableUpnp->setChecked(_settings->isUpnpEnabled());
00313 #endif
00314 }
00315 
00316 /** Shows exit policy related help information */
00317 void
00318 ServerPage::exitPolicyHelp()
00319 {
00320   emit helpRequested("server.exitpolicy");
00321 }
00322 
00323 /** Shows the bandwidth rate limiting help information */
00324 void
00325 ServerPage::bandwidthHelp()
00326 {
00327   emit helpRequested("server.bandwidth");
00328 }
00329 
00330 /** Loads the server's bandwidth average and burst limits. */
00331 void
00332 ServerPage::loadBandwidthLimits()
00333 {
00334   quint32 avgRate = _settings->getBandwidthAvgRate();
00335   quint32 maxRate = _settings->getBandwidthBurstRate();
00336 
00337   if (avgRate == CABLE256_AVG_RATE && 
00338       maxRate == CABLE256_MAX_RATE) {
00339     /* Cable/DSL 256 Kbps */
00340     ui.cmboRate->setCurrentIndex(CableDsl256); 
00341   } else if (avgRate == CABLE512_AVG_RATE && 
00342              maxRate == CABLE512_MAX_RATE) {
00343     /* Cable/DSL 512 Kbps */
00344     ui.cmboRate->setCurrentIndex(CableDsl512);
00345   } else if (avgRate == CABLE768_AVG_RATE && 
00346              maxRate == CABLE768_MAX_RATE) {
00347     /* Cable/DSL 768 Kbps */
00348     ui.cmboRate->setCurrentIndex(CableDsl768);
00349   } else if (avgRate == T1_AVG_RATE && 
00350              maxRate == T1_MAX_RATE) {
00351     /* T1/Cable/DSL 1.5 Mbps */
00352     ui.cmboRate->setCurrentIndex(T1CableDsl1500);
00353   } else if (avgRate == HIGHBW_AVG_RATE && 
00354              maxRate == HIGHBW_MAX_RATE) {
00355     /* > 1.5 Mbps */
00356     ui.cmboRate->setCurrentIndex(GreaterThan1500);
00357   } else {
00358     /* Custom bandwidth limits */
00359     ui.cmboRate->setCurrentIndex(CustomBwLimits);
00360   }
00361   /* Fill in the custom bandwidth limit boxes */
00362   ui.lineAvgRateLimit->setText(QString::number(avgRate/1024));
00363   ui.lineMaxRateLimit->setText(QString::number(maxRate/1024));
00364 }
00365 
00366 /** Saves the server's bandwidth average and burst limits. */
00367 void
00368 ServerPage::saveBandwidthLimits()
00369 {
00370   quint32 avgRate, maxRate;
00371 
00372   switch (ui.cmboRate->currentIndex()) {
00373     case CableDsl256: /* Cable/DSL 256 Kbps */
00374       avgRate = CABLE256_AVG_RATE;
00375       maxRate = CABLE256_MAX_RATE;
00376       break;
00377     case CableDsl512: /* Cable/DSL 512 Kbps */
00378       avgRate = CABLE512_AVG_RATE;
00379       maxRate = CABLE512_MAX_RATE;
00380       break;
00381     case CableDsl768: /* Cable/DSL 768 Kbps */
00382       avgRate = CABLE768_AVG_RATE;
00383       maxRate = CABLE768_MAX_RATE;
00384       break;
00385     case T1CableDsl1500: /* T1/Cable/DSL 1.5 Mbps */
00386       avgRate = T1_AVG_RATE;
00387       maxRate = T1_MAX_RATE;
00388       break;
00389     case GreaterThan1500: /* > 1.5 Mbps */
00390       avgRate = HIGHBW_AVG_RATE;
00391       maxRate = HIGHBW_MAX_RATE;
00392       break;
00393     default: /* Custom bandwidth limits */
00394       avgRate = (quint32)(ui.lineAvgRateLimit->text().toUInt()*1024);
00395       maxRate = (quint32)(ui.lineMaxRateLimit->text().toUInt()*1024);
00396       break;
00397   }
00398   _settings->setBandwidthAvgRate(avgRate);
00399   _settings->setBandwidthBurstRate(maxRate);
00400 }
00401 
00402 /** */
00403 void
00404 ServerPage::loadExitPolicies()
00405 {
00406   ExitPolicy exitPolicy = _settings->getExitPolicy();
00407   
00408   if (exitPolicy.contains(Policy(Policy::RejectAll))) {
00409     /* If the policy ends with reject *:*, check if the policy explicitly
00410      * accepts these ports */
00411     ui.chkWebsites->setChecked(exitPolicy.acceptsPorts(PORTS_HTTP));
00412     ui.chkSecWebsites->setChecked(exitPolicy.acceptsPorts(PORTS_HTTPS));
00413     ui.chkMail->setChecked(exitPolicy.acceptsPorts(PORTS_MAIL));
00414     ui.chkIRC->setChecked(exitPolicy.acceptsPorts(PORTS_IRC));
00415     ui.chkIM->setChecked(exitPolicy.acceptsPorts(PORTS_IM));
00416     ui.chkMisc->setChecked(false);
00417   } else {
00418     /* If the exit policy ends with accept *:*, check if the policy explicitly
00419      * rejects these ports */
00420     ui.chkWebsites->setChecked(!exitPolicy.rejectsPorts(PORTS_HTTP));
00421     ui.chkSecWebsites->setChecked(!exitPolicy.rejectsPorts(PORTS_HTTPS));
00422     ui.chkMail->setChecked(!exitPolicy.rejectsPorts(PORTS_MAIL));
00423     ui.chkIRC->setChecked(!exitPolicy.rejectsPorts(PORTS_IRC));
00424     ui.chkIM->setChecked(!exitPolicy.rejectsPorts(PORTS_IM));
00425     ui.chkMisc->setChecked(true);
00426   }
00427 }
00428 
00429 /** */
00430 void
00431 ServerPage::saveExitPolicies()
00432 {
00433   ExitPolicy exitPolicy;
00434   bool rejectUnchecked = ui.chkMisc->isChecked();
00435   
00436   /* If misc is checked, then reject unchecked items and leave the default exit
00437    * policy alone. Else, accept only checked items and end with reject *:*,
00438    * replacing the default exit policy. */
00439   if (ui.chkWebsites->isChecked() && !rejectUnchecked) {
00440     exitPolicy.addAcceptedPorts(PORTS_HTTP);
00441   } else if (!ui.chkWebsites->isChecked() && rejectUnchecked) {
00442     exitPolicy.addRejectedPorts(PORTS_HTTP);
00443   }
00444   if (ui.chkSecWebsites->isChecked() && !rejectUnchecked) {
00445     exitPolicy.addAcceptedPorts(PORTS_HTTPS);
00446   } else if (!ui.chkSecWebsites->isChecked() && rejectUnchecked) {
00447     exitPolicy.addRejectedPorts(PORTS_HTTPS);
00448   }
00449   if (ui.chkMail->isChecked() && !rejectUnchecked) {
00450     exitPolicy.addAcceptedPorts(PORTS_MAIL);
00451   } else if (!ui.chkMail->isChecked() && rejectUnchecked) {
00452     exitPolicy.addRejectedPorts(PORTS_MAIL);
00453   }
00454   if (ui.chkIRC->isChecked() && !rejectUnchecked) {
00455     exitPolicy.addAcceptedPorts(PORTS_IRC);
00456   } else if (!ui.chkIRC->isChecked() && rejectUnchecked) {
00457     exitPolicy.addRejectedPorts(PORTS_IRC);
00458   }
00459   if (ui.chkIM->isChecked() && !rejectUnchecked) {
00460     exitPolicy.addAcceptedPorts(PORTS_IM);
00461   } else if (!ui.chkIM->isChecked() && rejectUnchecked) {
00462     exitPolicy.addRejectedPorts(PORTS_IM);
00463   }
00464   if (!ui.chkMisc->isChecked()) {
00465     exitPolicy.addPolicy(Policy(Policy::RejectAll));
00466   }
00467   _settings->setExitPolicy(exitPolicy);
00468 }
00469 
00470 /** Called when the user selects a new value from the rate combo box. */
00471 void
00472 ServerPage::rateChanged(int index)
00473 {
00474   /* If the "Custom" option is selected, show the custom bandwidth 
00475    * limits form. */
00476   ui.frmCustomRate->setVisible(index == CustomBwLimits);
00477 }
00478 
00479 /** Called when the user edits the long-term average or maximum bandwidth limit. 
00480  * This ensures that the average bandwidth rate is greater than MIN_RATE
00481  * (20KB/s) and that the max rate is greater than the average rate. */
00482 void
00483 ServerPage::customRateChanged()
00484 {
00485   /* Make sure the average rate isn't too low or too high */
00486   quint32 avgRate = (quint32)ui.lineAvgRateLimit->text().toUInt();
00487   if (avgRate < MIN_BANDWIDTH_RATE) {
00488     ui.lineAvgRateLimit->setText(QString::number(MIN_BANDWIDTH_RATE));    
00489   }
00490   if (avgRate > MAX_BANDWIDTH_RATE) {
00491     ui.lineAvgRateLimit->setText(QString::number(MAX_BANDWIDTH_RATE));
00492   }
00493   /* Ensure the max burst rate is greater than the average rate but less than
00494    * the maximum allowed rate. */
00495   quint32 burstRate = (quint32)ui.lineMaxRateLimit->text().toUInt();
00496   if (avgRate > burstRate) {
00497     ui.lineMaxRateLimit->setText(QString::number(avgRate));
00498   }
00499   if (burstRate > MAX_BANDWIDTH_RATE) {
00500     ui.lineMaxRateLimit->setText(QString::number(MAX_BANDWIDTH_RATE));
00501   }
00502 }
00503 
00504 /** Tests automatic port forwarding using UPnP. */
00505 void
00506 ServerPage::testUpnp()
00507 {
00508 #if defined(USE_MINIUPNPC)
00509   UPNPTestDialog dlg(ui.lineServerPort->text().toUInt(),
00510                      ui.lineDirPort->text().toUInt(), this);
00511   
00512   connect(&dlg, SIGNAL(help()), this, SLOT(upnpHelp()));
00513 
00514   dlg.exec();
00515 #endif
00516 }
00517 
00518 /** Called when the user clicks the UPnP test dialog's help button. */
00519 void
00520 ServerPage::upnpHelp()
00521 {
00522   emit helpRequested("server.upnp");
00523 }
00524 

Generated on 2 Sep 2009 for Vidalia by  doxygen 1.6.1