• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

akonadi

selftestdialog.cpp
00001 /*
00002     Copyright (c) 2008 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "selftestdialog_p.h"
00021 #include "agentmanager.h"
00022 #include "dbusconnectionpool.h"
00023 #include "session_p.h"
00024 #include "servermanager_p.h"
00025 
00026 #include <akonadi/private/xdgbasedirs_p.h>
00027 
00028 #include <KDebug>
00029 #include <KIcon>
00030 #include <KFileDialog>
00031 #include <KLocale>
00032 #include <KMessageBox>
00033 #include <KRun>
00034 #include <KStandardDirs>
00035 #include <KUser>
00036 
00037 #include <QtCore/QFileInfo>
00038 #include <QtCore/QProcess>
00039 #include <QtCore/QSettings>
00040 #include <QtCore/QTextStream>
00041 #include <QtDBus/QtDBus>
00042 #include <QtGui/QApplication>
00043 #include <QtGui/QClipboard>
00044 #include <QtGui/QStandardItemModel>
00045 #include <QtSql/QSqlDatabase>
00046 #include <QtSql/QSqlError>
00047 
00048 // @cond PRIVATE
00049 
00050 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
00051 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
00052 #define AKONADI_SEARCH_SERVICE QLatin1String( "org.kde.nepomuk.services.nepomukqueryservice" )
00053 
00054 using namespace Akonadi;
00055 
00056 static QString makeLink( const QString &file )
00057 {
00058   return QString::fromLatin1( "<a href=\"%1\">%2</a>" ).arg( file, file );
00059 }
00060 
00061 enum SelfTestRole {
00062   ResultTypeRole = Qt::UserRole,
00063   FileIncludeRole,
00064   ListDirectoryRole,
00065   EnvVarRole,
00066   SummaryRole,
00067   DetailsRole
00068 };
00069 
00070 SelfTestDialog::SelfTestDialog(QWidget * parent) :
00071     KDialog( parent )
00072 {
00073   setCaption( i18n( "Akonadi Server Self-Test" ) );
00074   setButtons( Close | User1 | User2 );
00075   setButtonText( User1, i18n( "Save Report..." ) );
00076   setButtonIcon( User1, KIcon( QString::fromLatin1( "document-save" ) ) );
00077   setButtonText( User2, i18n( "Copy Report to Clipboard" ) );
00078   setButtonIcon( User2, KIcon( QString::fromLatin1( "edit-copy" ) ) );
00079   showButtonSeparator( true );
00080   ui.setupUi( mainWidget() );
00081 
00082   mTestModel = new QStandardItemModel( this );
00083   ui.testView->setModel( mTestModel );
00084   connect( ui.testView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00085            SLOT(selectionChanged(QModelIndex)) );
00086   connect( ui.detailsLabel, SIGNAL(linkActivated(QString)), SLOT(linkActivated(QString)) );
00087 
00088   connect( this, SIGNAL(user1Clicked()), SLOT(saveReport()) );
00089   connect( this, SIGNAL(user2Clicked()), SLOT(copyReport()) );
00090 
00091   connect( ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), SLOT(runTests()) );
00092   runTests();
00093 }
00094 
00095 void SelfTestDialog::hideIntroduction()
00096 {
00097   ui.introductionLabel->hide();
00098 }
00099 
00100 QStandardItem* SelfTestDialog::report( ResultType type, const KLocalizedString & summary, const KLocalizedString & details)
00101 {
00102   QStandardItem *item = new QStandardItem( summary.toString() );
00103   switch ( type ) {
00104     case Skip:
00105       item->setIcon( KIcon( QString::fromLatin1( "dialog-ok" ) ) );
00106       break;
00107     case Success:
00108       item->setIcon( KIcon( QString::fromLatin1( "dialog-ok-apply" ) ) );
00109       break;
00110     case Warning:
00111       item->setIcon( KIcon( QString::fromLatin1( "dialog-warning" ) ) );
00112       break;
00113     case Error:
00114     default:
00115       item->setIcon( KIcon( QString::fromLatin1( "dialog-error" ) ) );
00116   }
00117   item->setEditable( false );
00118   item->setWhatsThis( details.toString() );
00119   item->setData( type, ResultTypeRole );
00120   item->setData( summary.toString( 0 ), SummaryRole );
00121   item->setData( details.toString( 0 ), DetailsRole );
00122   mTestModel->appendRow( item );
00123   return item;
00124 }
00125 
00126 void SelfTestDialog::selectionChanged(const QModelIndex &index )
00127 {
00128   if ( index.isValid() ) {
00129     ui.detailsLabel->setText( index.data( Qt::WhatsThisRole ).toString() );
00130     ui.detailsGroup->setEnabled( true );
00131   } else {
00132     ui.detailsLabel->setText( QString() );
00133     ui.detailsGroup->setEnabled( false );
00134   }
00135 }
00136 
00137 void SelfTestDialog::runTests()
00138 {
00139   mTestModel->clear();
00140 
00141   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00142   testSQLDriver();
00143   if (driver == QLatin1String( "QPSQL" )) {
00144     testPSQLServer();
00145   }
00146   else {
00147 #ifndef Q_OS_WIN
00148     testRootUser();
00149 #endif
00150     testMySQLServer();
00151     testMySQLServerLog();
00152     testMySQLServerConfig();
00153   }
00154   testAkonadiCtl();
00155   testServerStatus();
00156   testSearchStatus();
00157   testProtocolVersion();
00158   testResources();
00159   testServerLog();
00160   testControlLog();
00161 }
00162 
00163 QVariant SelfTestDialog::serverSetting(const QString & group, const char *key, const QVariant &def ) const
00164 {
00165   const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
00166   QSettings settings( serverConfigFile, QSettings::IniFormat );
00167   settings.beginGroup( group );
00168   return settings.value( QString::fromLatin1(key), def );
00169 }
00170 
00171 bool SelfTestDialog::useStandaloneMysqlServer() const
00172 {
00173   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00174   if ( driver != QLatin1String( "QMYSQL" ) )
00175     return false;
00176   const bool startServer = serverSetting( driver, "StartServer", true ).toBool();
00177   if ( !startServer )
00178     return false;
00179   return true;
00180 }
00181 
00182 bool SelfTestDialog::runProcess(const QString & app, const QStringList & args, QString & result) const
00183 {
00184   QProcess proc;
00185   proc.start( app, args );
00186   const bool rv = proc.waitForFinished();
00187   result.clear();
00188   result += QString::fromLocal8Bit( proc.readAllStandardError() );
00189   result += QString::fromLocal8Bit( proc.readAllStandardOutput() );
00190   return rv;
00191 }
00192 
00193 void SelfTestDialog::testSQLDriver()
00194 {
00195   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00196   const QStringList availableDrivers = QSqlDatabase::drivers();
00197   const KLocalizedString detailsOk = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration and was found on your system." )
00198       .subs( driver );
00199   const KLocalizedString detailsFail = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration.\n"
00200       "The following drivers are installed: %2.\n"
00201       "Make sure the required driver is installed." )
00202       .subs( driver )
00203       .subs( availableDrivers.join( QLatin1String( ", " ) ) );
00204   QStandardItem *item = 0;
00205   if ( availableDrivers.contains( driver ) )
00206     item = report( Success, ki18n( "Database driver found." ), detailsOk );
00207   else
00208     item = report( Error, ki18n( "Database driver not found." ), detailsFail );
00209   item->setData( XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite ), FileIncludeRole );
00210 }
00211 
00212 void SelfTestDialog::testMySQLServer()
00213 {
00214   if ( !useStandaloneMysqlServer() ) {
00215     report( Skip, ki18n( "MySQL server executable not tested." ),
00216             ki18n( "The current configuration does not require an internal MySQL server." ) );
00217     return;
00218   }
00219 
00220   const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
00221   const QString serverPath = serverSetting( driver,  "ServerPath", QLatin1String( "" ) ).toString(); // ### default?
00222 
00223   const KLocalizedString details = ki18n( "You have currently configured Akonadi to use the MySQL server '%1'.\n"
00224       "Make sure you have the MySQL server installed, set the correct path and ensure you have the "
00225       "necessary read and execution rights on the server executable. The server executable is typically "
00226       "called 'mysqld'; its location varies depending on the distribution." ).subs( serverPath );
00227 
00228   QFileInfo info( serverPath );
00229   if ( !info.exists() )
00230     report( Error, ki18n( "MySQL server not found." ), details );
00231   else if ( !info.isReadable() )
00232     report( Error, ki18n( "MySQL server not readable." ), details );
00233   else if ( !info.isExecutable() )
00234     report( Error, ki18n( "MySQL server not executable." ), details );
00235   else if ( !serverPath.contains( QLatin1String( "mysqld" ) ) )
00236     report( Warning, ki18n( "MySQL found with unexpected name." ), details );
00237   else
00238     report( Success, ki18n( "MySQL server found." ), details );
00239 
00240   // be extra sure and get the server version while we are at it
00241   QString result;
00242   if ( runProcess( serverPath, QStringList() << QLatin1String( "--version" ), result ) ) {
00243     const KLocalizedString details = ki18n( "MySQL server found: %1" ).subs( result );
00244     report( Success, ki18n( "MySQL server is executable." ), details );
00245   } else {
00246     const KLocalizedString details = ki18n( "Executing the MySQL server '%1' failed with the following error message: '%2'" )
00247         .subs( serverPath ).subs( result );
00248     report( Error, ki18n( "Executing the MySQL server failed." ), details );
00249   }
00250 }
00251 
00252 void SelfTestDialog::testMySQLServerLog()
00253 {
00254   if ( !useStandaloneMysqlServer() ) {
00255     report( Skip, ki18n( "MySQL server error log not tested." ),
00256             ki18n( "The current configuration does not require an internal MySQL server." ) );
00257     return;
00258   }
00259 
00260   const QString logFileName = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) )
00261       + QDir::separator() + QString::fromLatin1( "mysql.err" );
00262   const QFileInfo logFileInfo( logFileName );
00263   if ( !logFileInfo.exists() || logFileInfo.size() == 0 ) {
00264     report( Success, ki18n( "No current MySQL error log found." ),
00265       ki18n( "The MySQL server did not report any errors during this startup. The log can be found in '%1'." ).subs( logFileName ) );
00266     return;
00267   }
00268   QFile logFile( logFileName );
00269   if ( !logFile.open( QFile::ReadOnly | QFile::Text  ) ) {
00270     report( Error, ki18n( "MySQL error log not readable." ),
00271       ki18n( "A MySQL server error log file was found but is not readable: %1" ).subs( makeLink( logFileName ) ) );
00272     return;
00273   }
00274   bool warningsFound = false;
00275   QStandardItem *item = 0;
00276   while ( !logFile.atEnd() ) {
00277     const QString line = QString::fromUtf8( logFile.readLine() );
00278     if ( line.contains( QLatin1String( "error" ), Qt::CaseInsensitive ) ) {
00279       item = report( Error, ki18n( "MySQL server log contains errors." ),
00280         ki18n( "The MySQL server error log file '%1' contains errors." ).subs( makeLink( logFileName ) ) );
00281       item->setData( logFileName, FileIncludeRole );
00282       return;
00283     }
00284     if ( !warningsFound && line.contains( QLatin1String( "warn" ), Qt::CaseInsensitive ) ) {
00285       warningsFound = true;
00286     }
00287   }
00288   if ( warningsFound ) {
00289     item = report( Warning, ki18n( "MySQL server log contains warnings." ),
00290                    ki18n( "The MySQL server log file '%1' contains warnings." ).subs( makeLink( logFileName ) ) );
00291   } else {
00292     item = report( Success, ki18n( "MySQL server log contains no errors." ),
00293                    ki18n( "The MySQL server log file '%1' does not contain any errors or warnings." )
00294                          .subs( makeLink( logFileName ) ) );
00295   }
00296   item->setData( logFileName, FileIncludeRole );
00297 
00298   logFile.close();
00299 }
00300 
00301 void SelfTestDialog::testMySQLServerConfig()
00302 {
00303   if ( !useStandaloneMysqlServer() ) {
00304     report( Skip, ki18n( "MySQL server configuration not tested." ),
00305             ki18n( "The current configuration does not require an internal MySQL server." ) );
00306     return;
00307   }
00308 
00309   QStandardItem *item = 0;
00310   const QString globalConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-global.conf" ) );
00311   const QFileInfo globalConfigInfo( globalConfig );
00312   if ( !globalConfig.isEmpty() && globalConfigInfo.exists() && globalConfigInfo.isReadable() ) {
00313     item = report( Success, ki18n( "MySQL server default configuration found." ),
00314                    ki18n( "The default configuration for the MySQL server was found and is readable at %1." )
00315                    .subs( makeLink( globalConfig ) ) );
00316     item->setData( globalConfig, FileIncludeRole );
00317   } else {
00318     report( Error, ki18n( "MySQL server default configuration not found." ),
00319             ki18n( "The default configuration for the MySQL server was not found or was not readable. "
00320                   "Check your Akonadi installation is complete and you have all required access rights." ) );
00321   }
00322 
00323   const QString localConfig  = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-local.conf" ) );
00324   const QFileInfo localConfigInfo( localConfig );
00325   if ( localConfig.isEmpty() || !localConfigInfo.exists() ) {
00326     report( Skip, ki18n( "MySQL server custom configuration not available." ),
00327             ki18n( "The custom configuration for the MySQL server was not found but is optional." ) );
00328   } else if ( localConfigInfo.exists() && localConfigInfo.isReadable() ) {
00329     item = report( Success, ki18n( "MySQL server custom configuration found." ),
00330                    ki18n( "The custom configuration for the MySQL server was found and is readable at %1" )
00331                    .subs( makeLink( localConfig ) ) );
00332     item->setData( localConfig, FileIncludeRole );
00333   } else {
00334     report( Error, ki18n( "MySQL server custom configuration not readable." ),
00335             ki18n( "The custom configuration for the MySQL server was found at %1 but is not readable. "
00336                   "Check your access rights." ).subs( makeLink( localConfig ) ) );
00337   }
00338 
00339   const QString actualConfig = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) + QLatin1String( "/mysql.conf" );
00340   const QFileInfo actualConfigInfo( actualConfig );
00341   if ( actualConfig.isEmpty() || !actualConfigInfo.exists() || !actualConfigInfo.isReadable() ) {
00342     report( Error, ki18n( "MySQL server configuration not found or not readable." ),
00343             ki18n( "The MySQL server configuration was not found or is not readable." ) );
00344   } else {
00345     item = report( Success, ki18n( "MySQL server configuration is usable." ),
00346                    ki18n( "The MySQL server configuration was found at %1 and is readable." ).subs( makeLink( actualConfig ) ) );
00347     item->setData( actualConfig, FileIncludeRole );
00348   }
00349 }
00350 
00351 void SelfTestDialog::testPSQLServer()
00352 {
00353   const QString dbname = serverSetting( QLatin1String( "QPSQL" ), "Name", QLatin1String( "akonadi" )).toString();
00354   const QString hostname = serverSetting( QLatin1String( "QPSQL" ), "Host", QLatin1String( "localhost" )).toString();
00355   const QString username = serverSetting( QLatin1String( "QPSQL" ), "User", QString() ).toString();
00356   const QString password = serverSetting( QLatin1String( "QPSQL" ), "Password", QString() ).toString();
00357   const int port = serverSetting( QLatin1String( "QPSQL" ), "Port", 5432).toInt();
00358 
00359   QSqlDatabase db = QSqlDatabase::addDatabase( QLatin1String( "QPSQL" ) );
00360   db.setHostName( hostname );
00361   db.setDatabaseName( dbname );
00362 
00363   if ( !username.isEmpty() )
00364     db.setUserName( username );
00365 
00366   if ( !password.isEmpty() )
00367     db.setPassword( password );
00368 
00369   db.setPort( port );
00370 
00371   if ( !db.open() ) {
00372     const KLocalizedString details = ki18n( db.lastError().text().toLatin1() );
00373     report( Error, ki18n( "Cannot connect to PostgreSQL server." ),  details);
00374   }
00375   else {
00376     report( Success, ki18n( "PostgreSQL server found." ),
00377                    ki18n( "The PostgreSQL server was found and connection is working." ));
00378   }
00379   db.close();
00380 }
00381 
00382 void SelfTestDialog::testAkonadiCtl()
00383 {
00384   const QString path = KStandardDirs::findExe( QLatin1String( "akonadictl" ) );
00385   if ( path.isEmpty() ) {
00386     report( Error, ki18n( "akonadictl not found" ),
00387                  ki18n( "The program 'akonadictl' needs to be accessible in $PATH. "
00388                        "Make sure you have the Akonadi server installed." ) );
00389     return;
00390   }
00391   QString result;
00392   if ( runProcess( path, QStringList() << QLatin1String( "--version" ), result ) ) {
00393     report( Success, ki18n( "akonadictl found and usable" ),
00394                    ki18n( "The program '%1' to control the Akonadi server was found "
00395                          "and could be executed successfully.\nResult:\n%2" ).subs( path ).subs( result ) );
00396   } else {
00397     report( Error, ki18n( "akonadictl found but not usable" ),
00398                  ki18n( "The program '%1' to control the Akonadi server was found "
00399                        "but could not be executed successfully.\nResult:\n%2\n"
00400                        "Make sure the Akonadi server is installed correctly." ).subs( path ).subs( result ) );
00401   }
00402 }
00403 
00404 void SelfTestDialog::testServerStatus()
00405 {
00406   if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE ) ) {
00407     report( Success, ki18n( "Akonadi control process registered at D-Bus." ),
00408                    ki18n( "The Akonadi control process is registered at D-Bus which typically indicates it is operational." ) );
00409   } else {
00410     report( Error, ki18n( "Akonadi control process not registered at D-Bus." ),
00411                  ki18n( "The Akonadi control process is not registered at D-Bus which typically means it was not started "
00412                        "or encountered a fatal error during startup."  ) );
00413   }
00414 
00415   if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE ) ) {
00416     report( Success, ki18n( "Akonadi server process registered at D-Bus." ),
00417                    ki18n( "The Akonadi server process is registered at D-Bus which typically indicates it is operational." ) );
00418   } else {
00419     report( Error, ki18n( "Akonadi server process not registered at D-Bus." ),
00420                  ki18n( "The Akonadi server process is not registered at D-Bus which typically means it was not started "
00421                        "or encountered a fatal error during startup."  ) );
00422   }
00423 }
00424 
00425 void SelfTestDialog::testSearchStatus()
00426 {
00427   bool searchAvailable = false;
00428   if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SEARCH_SERVICE ) ) {
00429     searchAvailable = true;
00430     report( Success, ki18n( "Nepomuk search service registered at D-Bus." ),
00431                    ki18n( "The Nepomuk search service is registered at D-Bus which typically indicates it is operational." ) );
00432   } else {
00433     report( Error, ki18n( "Nepomuk search service not registered at D-Bus." ),
00434                    ki18n( "The Nepomuk search service is not registered at D-Bus which typically means it was not started "
00435                           "or encountered a fatal error during startup."  ) );
00436   }
00437 
00438   if ( searchAvailable ) {
00439     // check which backend is used
00440     QDBusInterface interface( QLatin1String( "org.kde.NepomukStorage" ), QLatin1String( "/nepomukstorage" ) );
00441     const QDBusReply<QString> reply = interface.call( QLatin1String( "usedSopranoBackend" ) );
00442     if ( reply.isValid() ) {
00443       const QString name = reply.value();
00444 
00445       // put blacklisted backends here
00446       if ( name.contains( QLatin1String( "redland" ) ) ) {
00447         report( Error, ki18n( "Nepomuk search service uses inappropriate backend." ),
00448                        ki18n( "The Nepomuk search service uses the '%1' backend, which is not "
00449                               "recommended for use with Akonadi." ).subs( name ) );
00450       } else {
00451         report( Success, ki18n( "Nepomuk search service uses an appropriate backend. " ),
00452                          ki18n( "The Nepomuk search service uses one of the recommended backends." ) );
00453       }
00454     }
00455   }
00456 }
00457 
00458 void SelfTestDialog::testProtocolVersion()
00459 {
00460   if ( Internal::serverProtocolVersion() < 0 ) {
00461     report( Skip, ki18n( "Protocol version check not possible." ),
00462             ki18n( "Without a connection to the server it is not possible to check if the protocol version meets the requirements." ) );
00463     return;
00464   }
00465   if ( Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
00466     report( Error, ki18n( "Server protocol version is too old." ),
00467             ki18n( "The server protocol version is %1, but at least version %2 is required. "
00468                   "Install a newer version of the Akonadi server." )
00469                   .subs( Internal::serverProtocolVersion() )
00470                   .subs( SessionPrivate::minimumProtocolVersion() ) );
00471   } else {
00472     report( Success, ki18n( "Server protocol version is recent enough." ),
00473             ki18n( "The server Protocol version is %1, which equal or newer than the required version %2." )
00474                 .subs( Internal::serverProtocolVersion() )
00475                 .subs( SessionPrivate::minimumProtocolVersion() ) );
00476   }
00477 }
00478 
00479 void SelfTestDialog::testResources()
00480 {
00481   AgentType::List agentTypes = AgentManager::self()->types();
00482   bool resourceFound = false;
00483   foreach ( const AgentType &type, agentTypes ) {
00484     if ( type.capabilities().contains( QLatin1String( "Resource" ) ) ) {
00485       resourceFound = true;
00486       break;
00487     }
00488   }
00489 
00490   const QStringList pathList = XdgBaseDirs::findAllResourceDirs( "data", QLatin1String( "akonadi/agents" ) );
00491   QStandardItem *item = 0;
00492   if ( resourceFound ) {
00493     item = report( Success, ki18n( "Resource agents found." ), ki18n( "At least one resource agent has been found." ) );
00494   } else {
00495     item = report( Error, ki18n( "No resource agents found." ),
00496       ki18n( "No resource agents have been found, Akonadi is not usable without at least one. "
00497             "This usually means that no resource agents are installed or that there is a setup problem. "
00498             "The following paths have been searched: '%1'. "
00499             "The XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes all paths "
00500             "where Akonadi agents are installed." )
00501           .subs( pathList.join( QLatin1String( " " ) ) )
00502           .subs( QString::fromLocal8Bit( qgetenv( "XDG_DATA_DIRS" ) ) ) );
00503   }
00504   item->setData( pathList, ListDirectoryRole );
00505   item->setData( QByteArray( "XDG_DATA_DIRS" ), EnvVarRole );
00506 }
00507 
00508 void Akonadi::SelfTestDialog::testServerLog()
00509 {
00510   QString serverLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
00511       + QDir::separator() + QString::fromLatin1( "akonadiserver.error" );
00512   QFileInfo info( serverLog );
00513   if ( !info.exists() || info.size() <= 0 ) {
00514     report( Success, ki18n( "No current Akonadi server error log found." ),
00515                    ki18n( "The Akonadi server did not report any errors during its current startup." ) );
00516   } else {
00517     QStandardItem *item = report( Error, ki18n( "Current Akonadi server error log found." ),
00518       ki18n( "The Akonadi server reported errors during its current startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
00519     item->setData( serverLog, FileIncludeRole );
00520   }
00521 
00522   serverLog += QLatin1String( ".old" );
00523   info.setFile( serverLog );
00524   if ( !info.exists() || info.size() <= 0 ) {
00525     report( Success, ki18n( "No previous Akonadi server error log found." ),
00526                    ki18n( "The Akonadi server did not report any errors during its previous startup." ) );
00527   } else {
00528     QStandardItem *item = report( Error, ki18n( "Previous Akonadi server error log found." ),
00529       ki18n( "The Akonadi server reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
00530     item->setData( serverLog, FileIncludeRole );
00531   }
00532 }
00533 
00534 void SelfTestDialog::testControlLog()
00535 {
00536   QString controlLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
00537       + QDir::separator() + QString::fromLatin1( "akonadi_control.error" );
00538   QFileInfo info( controlLog );
00539   if ( !info.exists() || info.size() <= 0 ) {
00540     report( Success, ki18n( "No current Akonadi control error log found." ),
00541                    ki18n( "The Akonadi control process did not report any errors during its current startup." ) );
00542   } else {
00543     QStandardItem *item = report( Error, ki18n( "Current Akonadi control error log found." ),
00544       ki18n( "The Akonadi control process reported errors during its current startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
00545     item->setData( controlLog, FileIncludeRole );
00546   }
00547 
00548   controlLog += QLatin1String( ".old" );
00549   info.setFile( controlLog );
00550   if ( !info.exists() || info.size() <= 0 ) {
00551     report( Success, ki18n( "No previous Akonadi control error log found." ),
00552                    ki18n( "The Akonadi control process did not report any errors during its previous startup." ) );
00553   } else {
00554     QStandardItem *item = report( Error, ki18n( "Previous Akonadi control error log found." ),
00555       ki18n( "The Akonadi control process reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
00556     item->setData( controlLog, FileIncludeRole );
00557   }
00558 }
00559 
00560 
00561 void SelfTestDialog::testRootUser()
00562 {
00563   KUser user;
00564   if ( user.isSuperUser() ) {
00565     report( Error, ki18n( "Akonadi was started as root" ), ki18n( "Running Internet-facing applications as root/administrator exposes you to many security risks. MySQL, used by this Akonadi installation, will not allow itself to run as root, to protect you from these risks." ) );
00566   } else {
00567     report( Success, ki18n( "Akonadi is not running as root" ), ki18n( "Akonadi is not running as a root/administrator user, which is the recommended setup for a secure system." ) );
00568   }
00569 }
00570 
00571 QString SelfTestDialog::createReport()
00572 {
00573   QString result;
00574   QTextStream s( &result );
00575   s << "Akonadi Server Self-Test Report" << endl;
00576   s << "===============================" << endl;
00577 
00578   for ( int i = 0; i < mTestModel->rowCount(); ++i ) {
00579     QStandardItem *item = mTestModel->item( i );
00580     s << endl;
00581     s << "Test " << (i + 1) << ":  ";
00582     switch ( item->data( ResultTypeRole ).toInt() ) {
00583       case Skip:
00584         s << "SKIP"; break;
00585       case Success:
00586         s << "SUCCESS"; break;
00587       case Warning:
00588         s << "WARNING"; break;
00589       case Error:
00590       default:
00591         s << "ERROR"; break;
00592     }
00593     s << endl << "--------" << endl;
00594     s << endl;
00595     s << item->data( SummaryRole ).toString() << endl;
00596     s << "Details: " << item->data( DetailsRole ).toString() << endl;
00597     if ( item->data( FileIncludeRole ).isValid() ) {
00598       s << endl;
00599       const QString fileName = item->data( FileIncludeRole ).toString();
00600       QFile f( fileName );
00601       if ( f.open( QFile::ReadOnly ) ) {
00602         s << "File content of '" << fileName << "':" << endl;
00603         s << f.readAll() << endl;
00604       } else {
00605         s << "File '" << fileName << "' could not be opened" << endl;
00606       }
00607     }
00608     if ( item->data( ListDirectoryRole ).isValid() ) {
00609       s << endl;
00610       const QStringList pathList = item->data( ListDirectoryRole ).toStringList();
00611       if ( pathList.isEmpty() )
00612         s << "Directory list is empty." << endl;
00613       foreach ( const QString &path, pathList ) {
00614         s << "Directory listing of '" << path << "':" << endl;
00615         QDir dir( path );
00616         dir.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot );
00617         foreach ( const QString &entry, dir.entryList() )
00618           s << entry << endl;
00619       }
00620     }
00621     if ( item->data( EnvVarRole ).isValid() ) {
00622       s << endl;
00623       const QByteArray envVarName = item->data( EnvVarRole ).toByteArray();
00624       const QByteArray envVarValue = qgetenv( envVarName );
00625       s << "Environment variable " << envVarName << " is set to '" << envVarValue << "'" << endl;
00626     }
00627   }
00628 
00629   s << endl;
00630   s.flush();
00631   return result;
00632 }
00633 
00634 void SelfTestDialog::saveReport()
00635 {
00636   const QString defaultFileName = QLatin1String( "akonadi-selftest-report-" )
00637                    + QDate::currentDate().toString( QLatin1String( "yyyyMMdd" ) )
00638                    + QLatin1String( ".txt" );
00639   const QString fileName =  KFileDialog::getSaveFileName( defaultFileName, QString(), this,
00640                                                           i18n( "Save Test Report" ) );
00641   if ( fileName.isEmpty() )
00642     return;
00643 
00644   QFile file( fileName );
00645   if ( !file.open( QFile::ReadWrite ) ) {
00646     KMessageBox::error( this, i18n( "Could not open file '%1'", fileName ) );
00647     return;
00648   }
00649 
00650   file.write( createReport().toUtf8() );
00651   file.close();
00652 }
00653 
00654 void SelfTestDialog::copyReport()
00655 {
00656 #ifndef QT_NO_CLIPBOARD
00657   QApplication::clipboard()->setText( createReport() );
00658 #endif
00659 }
00660 
00661 void SelfTestDialog::linkActivated(const QString & link)
00662 {
00663   KRun::runUrl( KUrl::fromPath( link ), QLatin1String( "text/plain" ), this );
00664 }
00665 
00666 // @endcond
00667 
00668 #include "selftestdialog_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:00:45 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal