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

akonadi

  • akonadi
selftestdialog.cpp
1 /*
2  Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "selftestdialog_p.h"
21 #include "agentmanager.h"
22 #include "dbusconnectionpool.h"
23 #include "session_p.h"
24 #include "servermanager.h"
25 #include "servermanager_p.h"
26 
27 #include <akonadi/private/xdgbasedirs_p.h>
28 
29 #include <KDebug>
30 #include <KUrl>
31 #include <KIcon>
32 #include <KFileDialog>
33 #include <KLocalizedString>
34 #include <KMessageBox>
35 #include <KRun>
36 #include <KStandardDirs>
37 #include <KUser>
38 
39 #include <QtCore/QFileInfo>
40 #include <QtCore/QProcess>
41 #include <QtCore/QSettings>
42 #include <QtCore/QTextStream>
43 #include <QtDBus/QtDBus>
44 #include <QApplication>
45 #include <QClipboard>
46 #include <QStandardItemModel>
47 #include <QtSql/QSqlDatabase>
48 #include <QtSql/QSqlError>
49 
50 // @cond PRIVATE
51 
52 using namespace Akonadi;
53 
54 static QString makeLink( const QString &file )
55 {
56  return QString::fromLatin1( "<a href=\"%1\">%2</a>" ).arg( file, file );
57 }
58 
59 enum SelfTestRole {
60  ResultTypeRole = Qt::UserRole,
61  FileIncludeRole,
62  ListDirectoryRole,
63  EnvVarRole,
64  SummaryRole,
65  DetailsRole
66 };
67 
68 SelfTestDialog::SelfTestDialog(QWidget * parent) :
69  KDialog( parent )
70 {
71  setCaption( i18n( "Akonadi Server Self-Test" ) );
72  setButtons( Close | User1 | User2 );
73  setButtonText( User1, i18n( "Save Report..." ) );
74  setButtonIcon( User1, KIcon( QString::fromLatin1( "document-save" ) ) );
75  setButtonText( User2, i18n( "Copy Report to Clipboard" ) );
76  setButtonIcon( User2, KIcon( QString::fromLatin1( "edit-copy" ) ) );
77  showButtonSeparator( true );
78  ui.setupUi( mainWidget() );
79 
80  mTestModel = new QStandardItemModel( this );
81  ui.testView->setModel( mTestModel );
82  connect( ui.testView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
83  SLOT(selectionChanged(QModelIndex)) );
84  connect( ui.detailsLabel, SIGNAL(linkActivated(QString)), SLOT(linkActivated(QString)) );
85 
86  connect( this, SIGNAL(user1Clicked()), SLOT(saveReport()) );
87  connect( this, SIGNAL(user2Clicked()), SLOT(copyReport()) );
88 
89  connect( ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), SLOT(runTests()) );
90  runTests();
91 }
92 
93 void SelfTestDialog::hideIntroduction()
94 {
95  ui.introductionLabel->hide();
96 }
97 
98 QStandardItem* SelfTestDialog::report( ResultType type, const KLocalizedString & summary, const KLocalizedString & details)
99 {
100  QStandardItem *item = new QStandardItem( summary.toString() );
101  switch ( type ) {
102  case Skip:
103  item->setIcon( KIcon( QString::fromLatin1( "dialog-ok" ) ) );
104  break;
105  case Success:
106  item->setIcon( KIcon( QString::fromLatin1( "dialog-ok-apply" ) ) );
107  break;
108  case Warning:
109  item->setIcon( KIcon( QString::fromLatin1( "dialog-warning" ) ) );
110  break;
111  case Error:
112  default:
113  item->setIcon( KIcon( QString::fromLatin1( "dialog-error" ) ) );
114  }
115  item->setEditable( false );
116  item->setWhatsThis( details.toString() );
117  item->setData( type, ResultTypeRole );
118  item->setData( summary.toString( 0 ), SummaryRole );
119  item->setData( details.toString( 0 ), DetailsRole );
120  mTestModel->appendRow( item );
121  return item;
122 }
123 
124 void SelfTestDialog::selectionChanged(const QModelIndex &index )
125 {
126  if ( index.isValid() ) {
127  ui.detailsLabel->setText( index.data( Qt::WhatsThisRole ).toString() );
128  ui.detailsGroup->setEnabled( true );
129  } else {
130  ui.detailsLabel->setText( QString() );
131  ui.detailsGroup->setEnabled( false );
132  }
133 }
134 
135 void SelfTestDialog::runTests()
136 {
137  mTestModel->clear();
138 
139  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
140  testSQLDriver();
141  if (driver == QLatin1String( "QPSQL" )) {
142  testPSQLServer();
143  }
144  else {
145 #ifndef Q_OS_WIN
146  testRootUser();
147 #endif
148  testMySQLServer();
149  testMySQLServerLog();
150  testMySQLServerConfig();
151  }
152  testAkonadiCtl();
153  testServerStatus();
154  testProtocolVersion();
155  testResources();
156  testServerLog();
157  testControlLog();
158 }
159 
160 QVariant SelfTestDialog::serverSetting(const QString & group, const char *key, const QVariant &def ) const
161 {
162  const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
163  QSettings settings( serverConfigFile, QSettings::IniFormat );
164  settings.beginGroup( group );
165  return settings.value( QString::fromLatin1(key), def );
166 }
167 
168 bool SelfTestDialog::useStandaloneMysqlServer() const
169 {
170  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
171  if ( driver != QLatin1String( "QMYSQL" ) )
172  return false;
173  const bool startServer = serverSetting( driver, "StartServer", true ).toBool();
174  if ( !startServer )
175  return false;
176  return true;
177 }
178 
179 bool SelfTestDialog::runProcess(const QString & app, const QStringList & args, QString & result) const
180 {
181  QProcess proc;
182  proc.start( app, args );
183  const bool rv = proc.waitForFinished();
184  result.clear();
185  result += QString::fromLocal8Bit( proc.readAllStandardError() );
186  result += QString::fromLocal8Bit( proc.readAllStandardOutput() );
187  return rv;
188 }
189 
190 void SelfTestDialog::testSQLDriver()
191 {
192  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
193  const QStringList availableDrivers = QSqlDatabase::drivers();
194  const KLocalizedString detailsOk = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration and was found on your system." )
195  .subs( driver );
196  const KLocalizedString detailsFail = ki18n( "The QtSQL driver '%1' is required by your current Akonadi server configuration.\n"
197  "The following drivers are installed: %2.\n"
198  "Make sure the required driver is installed." )
199  .subs( driver )
200  .subs( availableDrivers.join( QLatin1String( ", " ) ) );
201  QStandardItem *item = 0;
202  if ( availableDrivers.contains( driver ) )
203  item = report( Success, ki18n( "Database driver found." ), detailsOk );
204  else
205  item = report( Error, ki18n( "Database driver not found." ), detailsFail );
206  item->setData( XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite ), FileIncludeRole );
207 }
208 
209 void SelfTestDialog::testMySQLServer()
210 {
211  if ( !useStandaloneMysqlServer() ) {
212  report( Skip, ki18n( "MySQL server executable not tested." ),
213  ki18n( "The current configuration does not require an internal MySQL server." ) );
214  return;
215  }
216 
217  const QString driver = serverSetting( QLatin1String( "General" ), "Driver", QLatin1String( "QMYSQL" ) ).toString();
218  const QString serverPath = serverSetting( driver, "ServerPath", QLatin1String( "" ) ).toString(); // ### default?
219 
220  const KLocalizedString details = ki18n( "You have currently configured Akonadi to use the MySQL server '%1'.\n"
221  "Make sure you have the MySQL server installed, set the correct path and ensure you have the "
222  "necessary read and execution rights on the server executable. The server executable is typically "
223  "called 'mysqld'; its location varies depending on the distribution." ).subs( serverPath );
224 
225  QFileInfo info( serverPath );
226  if ( !info.exists() )
227  report( Error, ki18n( "MySQL server not found." ), details );
228  else if ( !info.isReadable() )
229  report( Error, ki18n( "MySQL server not readable." ), details );
230  else if ( !info.isExecutable() )
231  report( Error, ki18n( "MySQL server not executable." ), details );
232  else if ( !serverPath.contains( QLatin1String( "mysqld" ) ) )
233  report( Warning, ki18n( "MySQL found with unexpected name." ), details );
234  else
235  report( Success, ki18n( "MySQL server found." ), details );
236 
237  // be extra sure and get the server version while we are at it
238  QString result;
239  if ( runProcess( serverPath, QStringList() << QLatin1String( "--version" ), result ) ) {
240  const KLocalizedString details = ki18n( "MySQL server found: %1" ).subs( result );
241  report( Success, ki18n( "MySQL server is executable." ), details );
242  } else {
243  const KLocalizedString details = ki18n( "Executing the MySQL server '%1' failed with the following error message: '%2'" )
244  .subs( serverPath ).subs( result );
245  report( Error, ki18n( "Executing the MySQL server failed." ), details );
246  }
247 }
248 
249 void SelfTestDialog::testMySQLServerLog()
250 {
251  if ( !useStandaloneMysqlServer() ) {
252  report( Skip, ki18n( "MySQL server error log not tested." ),
253  ki18n( "The current configuration does not require an internal MySQL server." ) );
254  return;
255  }
256 
257  const QString logFileName = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) )
258  + QDir::separator() + QString::fromLatin1( "mysql.err" );
259  const QFileInfo logFileInfo( logFileName );
260  if ( !logFileInfo.exists() || logFileInfo.size() == 0 ) {
261  report( Success, ki18n( "No current MySQL error log found." ),
262  ki18n( "The MySQL server did not report any errors during this startup. The log can be found in '%1'." ).subs( logFileName ) );
263  return;
264  }
265  QFile logFile( logFileName );
266  if ( !logFile.open( QFile::ReadOnly | QFile::Text ) ) {
267  report( Error, ki18n( "MySQL error log not readable." ),
268  ki18n( "A MySQL server error log file was found but is not readable: %1" ).subs( makeLink( logFileName ) ) );
269  return;
270  }
271  bool warningsFound = false;
272  QStandardItem *item = 0;
273  while ( !logFile.atEnd() ) {
274  const QString line = QString::fromUtf8( logFile.readLine() );
275  if ( line.contains( QLatin1String( "error" ), Qt::CaseInsensitive ) ) {
276  item = report( Error, ki18n( "MySQL server log contains errors." ),
277  ki18n( "The MySQL server error log file '%1' contains errors." ).subs( makeLink( logFileName ) ) );
278  item->setData( logFileName, FileIncludeRole );
279  return;
280  }
281  if ( !warningsFound && line.contains( QLatin1String( "warn" ), Qt::CaseInsensitive ) ) {
282  warningsFound = true;
283  }
284  }
285  if ( warningsFound ) {
286  item = report( Warning, ki18n( "MySQL server log contains warnings." ),
287  ki18n( "The MySQL server log file '%1' contains warnings." ).subs( makeLink( logFileName ) ) );
288  } else {
289  item = report( Success, ki18n( "MySQL server log contains no errors." ),
290  ki18n( "The MySQL server log file '%1' does not contain any errors or warnings." )
291  .subs( makeLink( logFileName ) ) );
292  }
293  item->setData( logFileName, FileIncludeRole );
294 
295  logFile.close();
296 }
297 
298 void SelfTestDialog::testMySQLServerConfig()
299 {
300  if ( !useStandaloneMysqlServer() ) {
301  report( Skip, ki18n( "MySQL server configuration not tested." ),
302  ki18n( "The current configuration does not require an internal MySQL server." ) );
303  return;
304  }
305 
306  QStandardItem *item = 0;
307  const QString globalConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-global.conf" ) );
308  const QFileInfo globalConfigInfo( globalConfig );
309  if ( !globalConfig.isEmpty() && globalConfigInfo.exists() && globalConfigInfo.isReadable() ) {
310  item = report( Success, ki18n( "MySQL server default configuration found." ),
311  ki18n( "The default configuration for the MySQL server was found and is readable at %1." )
312  .subs( makeLink( globalConfig ) ) );
313  item->setData( globalConfig, FileIncludeRole );
314  } else {
315  report( Error, ki18n( "MySQL server default configuration not found." ),
316  ki18n( "The default configuration for the MySQL server was not found or was not readable. "
317  "Check your Akonadi installation is complete and you have all required access rights." ) );
318  }
319 
320  const QString localConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-local.conf" ) );
321  const QFileInfo localConfigInfo( localConfig );
322  if ( localConfig.isEmpty() || !localConfigInfo.exists() ) {
323  report( Skip, ki18n( "MySQL server custom configuration not available." ),
324  ki18n( "The custom configuration for the MySQL server was not found but is optional." ) );
325  } else if ( localConfigInfo.exists() && localConfigInfo.isReadable() ) {
326  item = report( Success, ki18n( "MySQL server custom configuration found." ),
327  ki18n( "The custom configuration for the MySQL server was found and is readable at %1" )
328  .subs( makeLink( localConfig ) ) );
329  item->setData( localConfig, FileIncludeRole );
330  } else {
331  report( Error, ki18n( "MySQL server custom configuration not readable." ),
332  ki18n( "The custom configuration for the MySQL server was found at %1 but is not readable. "
333  "Check your access rights." ).subs( makeLink( localConfig ) ) );
334  }
335 
336  const QString actualConfig = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) + QLatin1String( "/mysql.conf" );
337  const QFileInfo actualConfigInfo( actualConfig );
338  if ( actualConfig.isEmpty() || !actualConfigInfo.exists() || !actualConfigInfo.isReadable() ) {
339  report( Error, ki18n( "MySQL server configuration not found or not readable." ),
340  ki18n( "The MySQL server configuration was not found or is not readable." ) );
341  } else {
342  item = report( Success, ki18n( "MySQL server configuration is usable." ),
343  ki18n( "The MySQL server configuration was found at %1 and is readable." ).subs( makeLink( actualConfig ) ) );
344  item->setData( actualConfig, FileIncludeRole );
345  }
346 }
347 
348 void SelfTestDialog::testPSQLServer()
349 {
350  const QString dbname = serverSetting( QLatin1String( "QPSQL" ), "Name", QLatin1String( "akonadi" )).toString();
351  const QString hostname = serverSetting( QLatin1String( "QPSQL" ), "Host", QLatin1String( "localhost" )).toString();
352  const QString username = serverSetting( QLatin1String( "QPSQL" ), "User", QString() ).toString();
353  const QString password = serverSetting( QLatin1String( "QPSQL" ), "Password", QString() ).toString();
354  const int port = serverSetting( QLatin1String( "QPSQL" ), "Port", 5432).toInt();
355 
356  QSqlDatabase db = QSqlDatabase::addDatabase( QLatin1String( "QPSQL" ) );
357  db.setHostName( hostname );
358  db.setDatabaseName( dbname );
359 
360  if ( !username.isEmpty() )
361  db.setUserName( username );
362 
363  if ( !password.isEmpty() )
364  db.setPassword( password );
365 
366  db.setPort( port );
367 
368  if ( !db.open() ) {
369  const KLocalizedString details = ki18n( db.lastError().text().toLatin1() );
370  report( Error, ki18n( "Cannot connect to PostgreSQL server." ), details);
371  }
372  else {
373  report( Success, ki18n( "PostgreSQL server found." ),
374  ki18n( "The PostgreSQL server was found and connection is working." ));
375  }
376  db.close();
377 }
378 
379 void SelfTestDialog::testAkonadiCtl()
380 {
381  const QString path = KStandardDirs::findExe( QLatin1String( "akonadictl" ) );
382  if ( path.isEmpty() ) {
383  report( Error, ki18n( "akonadictl not found" ),
384  ki18n( "The program 'akonadictl' needs to be accessible in $PATH. "
385  "Make sure you have the Akonadi server installed." ) );
386  return;
387  }
388  QString result;
389  if ( runProcess( path, QStringList() << QLatin1String( "--version" ), result ) ) {
390  report( Success, ki18n( "akonadictl found and usable" ),
391  ki18n( "The program '%1' to control the Akonadi server was found "
392  "and could be executed successfully.\nResult:\n%2" ).subs( path ).subs( result ) );
393  } else {
394  report( Error, ki18n( "akonadictl found but not usable" ),
395  ki18n( "The program '%1' to control the Akonadi server was found "
396  "but could not be executed successfully.\nResult:\n%2\n"
397  "Make sure the Akonadi server is installed correctly." ).subs( path ).subs( result ) );
398  }
399 }
400 
401 void SelfTestDialog::testServerStatus()
402 {
403  if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName(ServerManager::Control) ) ) {
404  report( Success, ki18n( "Akonadi control process registered at D-Bus." ),
405  ki18n( "The Akonadi control process is registered at D-Bus which typically indicates it is operational." ) );
406  } else {
407  report( Error, ki18n( "Akonadi control process not registered at D-Bus." ),
408  ki18n( "The Akonadi control process is not registered at D-Bus which typically means it was not started "
409  "or encountered a fatal error during startup." ) );
410  }
411 
412  if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName(ServerManager::Server) ) ) {
413  report( Success, ki18n( "Akonadi server process registered at D-Bus." ),
414  ki18n( "The Akonadi server process is registered at D-Bus which typically indicates it is operational." ) );
415  } else {
416  report( Error, ki18n( "Akonadi server process not registered at D-Bus." ),
417  ki18n( "The Akonadi server process is not registered at D-Bus which typically means it was not started "
418  "or encountered a fatal error during startup." ) );
419  }
420 }
421 
422 void SelfTestDialog::testProtocolVersion()
423 {
424  if ( Internal::serverProtocolVersion() < 0 ) {
425  report( Skip, ki18n( "Protocol version check not possible." ),
426  ki18n( "Without a connection to the server it is not possible to check if the protocol version meets the requirements." ) );
427  return;
428  }
429  if ( Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
430  report( Error, ki18n( "Server protocol version is too old." ),
431  ki18n( "The server protocol version is %1, but at least version %2 is required. "
432  "Install a newer version of the Akonadi server." )
433  .subs( Internal::serverProtocolVersion() )
434  .subs( SessionPrivate::minimumProtocolVersion() ) );
435  } else {
436  report( Success, ki18n( "Server protocol version is recent enough." ),
437  ki18n( "The server Protocol version is %1, which equal or newer than the required version %2." )
438  .subs( Internal::serverProtocolVersion() )
439  .subs( SessionPrivate::minimumProtocolVersion() ) );
440  }
441 }
442 
443 void SelfTestDialog::testResources()
444 {
445  AgentType::List agentTypes = AgentManager::self()->types();
446  bool resourceFound = false;
447  foreach ( const AgentType &type, agentTypes ) {
448  if ( type.capabilities().contains( QLatin1String( "Resource" ) ) ) {
449  resourceFound = true;
450  break;
451  }
452  }
453 
454  const QStringList pathList = XdgBaseDirs::findAllResourceDirs( "data", QLatin1String( "akonadi/agents" ) );
455  QStandardItem *item = 0;
456  if ( resourceFound ) {
457  item = report( Success, ki18n( "Resource agents found." ), ki18n( "At least one resource agent has been found." ) );
458  } else {
459  item = report( Error, ki18n( "No resource agents found." ),
460  ki18n( "No resource agents have been found, Akonadi is not usable without at least one. "
461  "This usually means that no resource agents are installed or that there is a setup problem. "
462  "The following paths have been searched: '%1'. "
463  "The XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes all paths "
464  "where Akonadi agents are installed." )
465  .subs( pathList.join( QLatin1String( " " ) ) )
466  .subs( QString::fromLocal8Bit( qgetenv( "XDG_DATA_DIRS" ) ) ) );
467  }
468  item->setData( pathList, ListDirectoryRole );
469  item->setData( QByteArray( "XDG_DATA_DIRS" ), EnvVarRole );
470 }
471 
472 void Akonadi::SelfTestDialog::testServerLog()
473 {
474  QString serverLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
475  + QDir::separator() + QString::fromLatin1( "akonadiserver.error" );
476  QFileInfo info( serverLog );
477  if ( !info.exists() || info.size() <= 0 ) {
478  report( Success, ki18n( "No current Akonadi server error log found." ),
479  ki18n( "The Akonadi server did not report any errors during its current startup." ) );
480  } else {
481  QStandardItem *item = report( Error, ki18n( "Current Akonadi server error log found." ),
482  ki18n( "The Akonadi server reported errors during its current startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
483  item->setData( serverLog, FileIncludeRole );
484  }
485 
486  serverLog += QLatin1String( ".old" );
487  info.setFile( serverLog );
488  if ( !info.exists() || info.size() <= 0 ) {
489  report( Success, ki18n( "No previous Akonadi server error log found." ),
490  ki18n( "The Akonadi server did not report any errors during its previous startup." ) );
491  } else {
492  QStandardItem *item = report( Error, ki18n( "Previous Akonadi server error log found." ),
493  ki18n( "The Akonadi server reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
494  item->setData( serverLog, FileIncludeRole );
495  }
496 }
497 
498 void SelfTestDialog::testControlLog()
499 {
500  QString controlLog = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) )
501  + QDir::separator() + QString::fromLatin1( "akonadi_control.error" );
502  QFileInfo info( controlLog );
503  if ( !info.exists() || info.size() <= 0 ) {
504  report( Success, ki18n( "No current Akonadi control error log found." ),
505  ki18n( "The Akonadi control process did not report any errors during its current startup." ) );
506  } else {
507  QStandardItem *item = report( Error, ki18n( "Current Akonadi control error log found." ),
508  ki18n( "The Akonadi control process reported errors during its current startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
509  item->setData( controlLog, FileIncludeRole );
510  }
511 
512  controlLog += QLatin1String( ".old" );
513  info.setFile( controlLog );
514  if ( !info.exists() || info.size() <= 0 ) {
515  report( Success, ki18n( "No previous Akonadi control error log found." ),
516  ki18n( "The Akonadi control process did not report any errors during its previous startup." ) );
517  } else {
518  QStandardItem *item = report( Error, ki18n( "Previous Akonadi control error log found." ),
519  ki18n( "The Akonadi control process reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
520  item->setData( controlLog, FileIncludeRole );
521  }
522 }
523 
524 void SelfTestDialog::testRootUser()
525 {
526  KUser user;
527  if ( user.isSuperUser() ) {
528  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." ) );
529  } else {
530  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." ) );
531  }
532 }
533 
534 QString SelfTestDialog::createReport()
535 {
536  QString result;
537  QTextStream s( &result );
538  s << "Akonadi Server Self-Test Report" << endl;
539  s << "===============================" << endl;
540 
541  for ( int i = 0; i < mTestModel->rowCount(); ++i ) {
542  QStandardItem *item = mTestModel->item( i );
543  s << endl;
544  s << "Test " << (i + 1) << ": ";
545  switch ( item->data( ResultTypeRole ).toInt() ) {
546  case Skip:
547  s << "SKIP"; break;
548  case Success:
549  s << "SUCCESS"; break;
550  case Warning:
551  s << "WARNING"; break;
552  case Error:
553  default:
554  s << "ERROR"; break;
555  }
556  s << endl << "--------" << endl;
557  s << endl;
558  s << item->data( SummaryRole ).toString() << endl;
559  s << "Details: " << item->data( DetailsRole ).toString() << endl;
560  if ( item->data( FileIncludeRole ).isValid() ) {
561  s << endl;
562  const QString fileName = item->data( FileIncludeRole ).toString();
563  QFile f( fileName );
564  if ( f.open( QFile::ReadOnly ) ) {
565  s << "File content of '" << fileName << "':" << endl;
566  s << f.readAll() << endl;
567  } else {
568  s << "File '" << fileName << "' could not be opened" << endl;
569  }
570  }
571  if ( item->data( ListDirectoryRole ).isValid() ) {
572  s << endl;
573  const QStringList pathList = item->data( ListDirectoryRole ).toStringList();
574  if ( pathList.isEmpty() )
575  s << "Directory list is empty." << endl;
576  foreach ( const QString &path, pathList ) {
577  s << "Directory listing of '" << path << "':" << endl;
578  QDir dir( path );
579  dir.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot );
580  foreach ( const QString &entry, dir.entryList() )
581  s << entry << endl;
582  }
583  }
584  if ( item->data( EnvVarRole ).isValid() ) {
585  s << endl;
586  const QByteArray envVarName = item->data( EnvVarRole ).toByteArray();
587  const QByteArray envVarValue = qgetenv( envVarName );
588  s << "Environment variable " << envVarName << " is set to '" << envVarValue << "'" << endl;
589  }
590  }
591 
592  s << endl;
593  s.flush();
594  return result;
595 }
596 
597 void SelfTestDialog::saveReport()
598 {
599  const QString defaultFileName = QLatin1String( "akonadi-selftest-report-" )
600  + QDate::currentDate().toString( QLatin1String( "yyyyMMdd" ) )
601  + QLatin1String( ".txt" );
602  const QString fileName = KFileDialog::getSaveFileName( QUrl(defaultFileName), QString(), this,
603  i18n( "Save Test Report" ) );
604  if ( fileName.isEmpty() )
605  return;
606 
607  QFile file( fileName );
608  if ( !file.open( QFile::ReadWrite ) ) {
609  KMessageBox::error( this, i18n( "Could not open file '%1'", fileName ) );
610  return;
611  }
612 
613  file.write( createReport().toUtf8() );
614  file.close();
615 }
616 
617 void SelfTestDialog::copyReport()
618 {
619 #ifndef QT_NO_CLIPBOARD
620  QApplication::clipboard()->setText( createReport() );
621 #endif
622 }
623 
624 void SelfTestDialog::linkActivated(const QString & link)
625 {
626  KRun::runUrl( KUrl::fromPath( link ), QLatin1String( "text/plain" ), this );
627 }
628 
629 // @endcond
630 
631 #include "moc_selftestdialog_p.cpp"
Akonadi::ServerManager::self
static ServerManager * self()
Returns the singleton instance of this class, for connecting to its signals.
Definition: servermanager.cpp:161
Akonadi::SelfTestDialog::hideIntroduction
void hideIntroduction()
Hides the label with the introduction message.
Akonadi::ServerManager::serviceName
static QString serviceName(ServiceType serviceType)
Returns the namespaced D-Bus service name for serviceType.
Definition: servermanager.cpp:305
Akonadi::AgentType
A representation of an agent type.
Definition: agenttype.h:58
Akonadi::AgentType::List
QList< AgentType > List
Describes a list of agent types.
Definition: agenttype.h:67
Akonadi::AgentType::capabilities
QStringList capabilities() const
Returns the list of supported capabilities of the agent type.
Definition: agenttype.cpp:76
Akonadi::SelfTestDialog::SelfTestDialog
SelfTestDialog(QWidget *parent=0)
Creates a new self test dialog.
Akonadi::AgentManager::types
AgentType::List types() const
Returns the list of all available agent types.
Definition: agentmanager.cpp:389
Akonadi::AgentManager::self
static AgentManager * self()
Returns the global instance of the agent manager.
Definition: agentmanager.cpp:380
Akonadi::ServerManager::State
State
Enum for the various states the server can be in.
Definition: servermanager.h:50
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Mon Jul 21 2014 08:03:55 by doxygen 1.8.6 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.13.3 API Reference

Skip menu "kdepimlibs-4.13.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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