00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kalarm.h"
00022
00023 #include <qtimer.h>
00024 #include <qiconset.h>
00025
00026 #include <kstandarddirs.h>
00027 #include <kconfig.h>
00028 #include <kaboutdata.h>
00029 #include <kmessagebox.h>
00030 #include <dcopclient.h>
00031 #include <kdebug.h>
00032
00033 #include "kalarmd/kalarmd.h"
00034 #include "kalarmd/alarmdaemoniface.h"
00035 #include "kalarmd/alarmdaemoniface_stub.h"
00036 #include "kalarmd/alarmguiiface.h"
00037
00038 #include "alarmcalendar.h"
00039 #include "kalarmapp.h"
00040 #include "preferences.h"
00041 #include "daemon.moc"
00042
00043
00044 static const int REGISTER_TIMEOUT = 20;
00045 static const char* NOTIFY_DCOP_OBJECT = "notify";
00046
00047 static QString expandURL(const QString& urlString);
00048
00049
00050
00051
00052
00053
00054
00055 class NotificationHandler : public QObject, virtual public AlarmGuiIface
00056 {
00057 public:
00058 NotificationHandler();
00059 private:
00060
00061 void alarmDaemonUpdate(int calendarStatus, const QString& calendarURL);
00062 void handleEvent(const QString& calendarURL, const QString& eventID);
00063 void registered(bool reregister, int result);
00064 };
00065
00066
00067 Daemon* Daemon::mInstance = 0;
00068 NotificationHandler* Daemon::mDcopHandler = 0;
00069 QTimer* Daemon::mStartTimer = 0;
00070 QTimer* Daemon::mRegisterTimer = 0;
00071 QTimer* Daemon::mStatusTimer = 0;
00072 int Daemon::mStatusTimerCount = 0;
00073 int Daemon::mStatusTimerInterval;
00074 int Daemon::mStartTimeout = 0;
00075 Daemon::Status Daemon::mStatus = Daemon::STOPPED;
00076 bool Daemon::mRunning = false;
00077 bool Daemon::mCalendarDisabled = false;
00078 bool Daemon::mEnableCalPending = false;
00079 bool Daemon::mRegisterFailMsg = false;
00080
00081
00082
00083
00084 static const int startCheckInterval = 500;
00085
00086
00087
00088
00089
00090
00091
00092 void Daemon::initialise()
00093 {
00094 if (!mInstance)
00095 mInstance = new Daemon();
00096 connect(AlarmCalendar::activeCalendar(), SIGNAL(calendarSaved(AlarmCalendar*)), mInstance, SLOT(slotCalendarSaved(AlarmCalendar*)));
00097 }
00098
00099
00100
00101
00102 void Daemon::createDcopHandler()
00103 {
00104 if (mDcopHandler)
00105 return;
00106 mDcopHandler = new NotificationHandler();
00107
00108
00109 mRunning = isRunning(false);
00110
00111 mStatusTimerInterval = Preferences::daemonTrayCheckInterval();
00112 Preferences::connect(SIGNAL(preferencesChanged()), mInstance, SLOT(slotPreferencesChanged()));
00113
00114 mStatusTimer = new QTimer(mInstance);
00115 connect(mStatusTimer, SIGNAL(timeout()), mInstance, SLOT(timerCheckIfRunning()));
00116 mStatusTimer->start(mStatusTimerInterval * 1000);
00117 }
00118
00119
00120
00121
00122
00123 bool Daemon::start()
00124 {
00125 kdDebug(5950) << "Daemon::start()\n";
00126 updateRegisteredStatus();
00127 switch (mStatus)
00128 {
00129 case STOPPED:
00130 {
00131 if (mStartTimer)
00132 return true;
00133
00134
00135 QString execStr = locate("exe", QString::fromLatin1(DAEMON_APP_NAME));
00136 if (execStr.isEmpty())
00137 {
00138 KMessageBox::error(0, i18n("Alarm daemon not found."));
00139 kdError() << "Daemon::startApp(): " DAEMON_APP_NAME " not found" << endl;
00140 return false;
00141 }
00142 KApplication::kdeinitExec(execStr);
00143 kdDebug(5950) << "Daemon::start(): Alarm daemon started" << endl;
00144 mStartTimeout = 5000/startCheckInterval + 1;
00145 mStartTimer = new QTimer(mInstance);
00146 connect(mStartTimer, SIGNAL(timeout()), mInstance, SLOT(checkIfStarted()));
00147 mStartTimer->start(startCheckInterval);
00148 mInstance->checkIfStarted();
00149 return true;
00150 }
00151 case RUNNING:
00152 return true;
00153 case READY:
00154
00155 if (!registerWith(false))
00156 return false;
00157 break;
00158 case REGISTERED:
00159 break;
00160 }
00161 return true;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170 bool Daemon::registerWith(bool reregister)
00171 {
00172 if (mRegisterTimer)
00173 return true;
00174 if (mStatus == STOPPED || mStatus == RUNNING)
00175 return false;
00176 if (mStatus == REGISTERED && !reregister)
00177 return true;
00178
00179 bool disabledIfStopped = theApp()->alarmsDisabledIfStopped();
00180 kdDebug(5950) << (reregister ? "Daemon::reregisterWith(): " : "Daemon::registerWith(): ") << (disabledIfStopped ? "NO_START" : "COMMAND_LINE") << endl;
00181 QCString appname = kapp->aboutData()->appName();
00182 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00183 if (reregister)
00184 s.registerChange(appname, !disabledIfStopped);
00185 else
00186 s.registerApp(appname, kapp->aboutData()->programName(), QCString(NOTIFY_DCOP_OBJECT), AlarmCalendar::activeCalendar()->urlString(), !disabledIfStopped);
00187 if (!s.ok())
00188 {
00189 registrationResult(reregister, KAlarmd::FAILURE);
00190 return false;
00191 }
00192 mRegisterTimer = new QTimer(mInstance);
00193 connect(mRegisterTimer, SIGNAL(timeout()), mInstance, SLOT(registerTimerExpired()));
00194 mRegisterTimer->start(REGISTER_TIMEOUT * 1000);
00195 return true;
00196 }
00197
00198
00199
00200
00201 void Daemon::registrationResult(bool reregister, int result)
00202 {
00203 kdDebug(5950) << "Daemon::registrationResult(" << reregister << ")\n";
00204 delete mRegisterTimer;
00205 mRegisterTimer = 0;
00206 switch (result)
00207 {
00208 case KAlarmd::SUCCESS:
00209 break;
00210 case KAlarmd::NOT_FOUND:
00211 kdError(5950) << "Daemon::registrationResult(" << reregister << "): registerApp dcop call: " << kapp->aboutData()->appName() << " not found\n";
00212 KMessageBox::error(0, i18n("Alarms will be disabled if you stop KAlarm.\n"
00213 "(Installation or configuration error: %1 cannot locate %2 executable.)")
00214 .arg(QString::fromLatin1(DAEMON_APP_NAME))
00215 .arg(kapp->aboutData()->appName()));
00216 break;
00217 case KAlarmd::FAILURE:
00218 default:
00219 kdError(5950) << "Daemon::registrationResult(" << reregister << "): registerApp dcop call failed -> " << result << endl;
00220 if (!reregister)
00221 {
00222 if (mStatus == REGISTERED)
00223 mStatus = READY;
00224 if (!mRegisterFailMsg)
00225 {
00226 mRegisterFailMsg = true;
00227 KMessageBox::error(0, i18n("Cannot enable alarms:\nFailed to register with Alarm Daemon (%1)")
00228 .arg(QString::fromLatin1(DAEMON_APP_NAME)));
00229 }
00230 }
00231 return;
00232 }
00233
00234 if (!reregister)
00235 {
00236
00237 mStatus = REGISTERED;
00238 mRegisterFailMsg = false;
00239 kdDebug(5950) << "Daemon::start(): daemon startup complete" << endl;
00240 }
00241 }
00242
00243
00244
00245
00246 void Daemon::checkIfStarted()
00247 {
00248 updateRegisteredStatus();
00249 bool err = false;
00250 switch (mStatus)
00251 {
00252 case STOPPED:
00253 if (--mStartTimeout > 0)
00254 return;
00255
00256
00257 err = true;
00258 break;
00259 case RUNNING:
00260 case READY:
00261 case REGISTERED:
00262 break;
00263 }
00264 delete mStartTimer;
00265 mStartTimer = 0;
00266 if (err)
00267 {
00268 kdError(5950) << "Daemon::checkIfStarted(): failed to start daemon" << endl;
00269 KMessageBox::error(0, i18n("Cannot enable alarms:\nFailed to start Alarm Daemon (%1)").arg(QString::fromLatin1(DAEMON_APP_NAME)));
00270 }
00271 }
00272
00273
00274
00275
00276
00277 void Daemon::updateRegisteredStatus(bool timeout)
00278 {
00279 if (!kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00280 {
00281 mStatus = STOPPED;
00282 mRegisterFailMsg = false;
00283 }
00284 else
00285 {
00286 switch (mStatus)
00287 {
00288 case STOPPED:
00289
00290
00291 mStatus = RUNNING;
00292 QTimer::singleShot(startCheckInterval, mInstance, SLOT(slotStarted()));
00293 break;
00294 case RUNNING:
00295 if (timeout)
00296 {
00297 mStatus = READY;
00298 start();
00299 }
00300 break;
00301 case READY:
00302 case REGISTERED:
00303 break;
00304 }
00305 }
00306 kdDebug(5950) << "Daemon::updateRegisteredStatus() -> " << mStatus << endl;
00307 }
00308
00309
00310
00311
00312 bool Daemon::stop()
00313 {
00314 kdDebug(5950) << "Daemon::stop()" << endl;
00315 if (kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00316 {
00317 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00318 s.quit();
00319 if (!s.ok())
00320 {
00321 kdError(5950) << "Daemon::stop(): dcop call failed" << endl;
00322 return false;
00323 }
00324 }
00325 return true;
00326 }
00327
00328
00329
00330
00331
00332
00333 bool Daemon::reset()
00334 {
00335 kdDebug(5950) << "Daemon::reset()" << endl;
00336 if (!kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00337 return false;
00338 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00339 s.resetCalendar(QCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString());
00340 if (!s.ok())
00341 kdError(5950) << "Daemon::reset(): resetCalendar dcop send failed" << endl;
00342 return true;
00343 }
00344
00345
00346
00347
00348 void Daemon::reload()
00349 {
00350 kdDebug(5950) << "Daemon::reload()\n";
00351 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00352 s.reloadCalendar(QCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString());
00353 if (!s.ok())
00354 kdError(5950) << "Daemon::reload(): reloadCalendar dcop send failed" << endl;
00355 }
00356
00357
00358
00359
00360 void Daemon::enableCalendar(bool enable)
00361 {
00362 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00363 s.enableCalendar(AlarmCalendar::activeCalendar()->urlString(), enable);
00364 mEnableCalPending = false;
00365 }
00366
00367
00368
00369
00370 void Daemon::enableAutoStart(bool enable)
00371 {
00372
00373 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00374 s.enableAutoStart(enable);
00375 if (!s.ok())
00376 {
00377
00378 KConfig adconfig(locate("config", DAEMON_APP_NAME"rc"));
00379 adconfig.setGroup(QString::fromLatin1(DAEMON_AUTOSTART_SECTION));
00380 adconfig.writeEntry(QString::fromLatin1(DAEMON_AUTOSTART_KEY), enable);
00381 adconfig.sync();
00382 }
00383 }
00384
00385
00386
00387
00388 bool Daemon::autoStart(bool defaultAutoStart)
00389 {
00390 KConfig adconfig(locate("config", DAEMON_APP_NAME"rc"));
00391 adconfig.setGroup(QString::fromLatin1(DAEMON_AUTOSTART_SECTION));
00392 return adconfig.readBoolEntry(QString::fromLatin1(DAEMON_AUTOSTART_KEY), defaultAutoStart);
00393 }
00394
00395
00396
00397
00398
00399 void Daemon::calendarIsEnabled(bool enabled)
00400 {
00401 mCalendarDisabled = !enabled;
00402 emit mInstance->daemonRunning(enabled);
00403 }
00404
00405
00406
00407
00408
00409 void Daemon::setAlarmsEnabled(bool enable)
00410 {
00411 kdDebug(5950) << "Daemon::setAlarmsEnabled(" << enable << ")\n";
00412 if (enable && !checkIfRunning())
00413 {
00414
00415 if (!start())
00416 {
00417 emit daemonRunning(false);
00418 return;
00419 }
00420 mEnableCalPending = true;
00421 setFastCheck();
00422 }
00423
00424
00425 if (checkIfRunning())
00426 enableCalendar(enable);
00427 }
00428
00429
00430
00431
00432 bool Daemon::monitoringAlarms()
00433 {
00434 bool ok = !mCalendarDisabled && isRunning();
00435 emit mInstance->daemonRunning(ok);
00436 return ok;
00437 }
00438
00439
00440
00441
00442 bool Daemon::isRunning(bool startdaemon)
00443 {
00444 static bool runState = false;
00445 updateRegisteredStatus();
00446 bool newRunState = (mStatus == READY || mStatus == REGISTERED);
00447 if (newRunState != runState)
00448 {
00449
00450 runState = newRunState;
00451 if (runState && startdaemon)
00452 start();
00453 }
00454 return runState && (mStatus == REGISTERED);
00455 }
00456
00457
00458
00459
00460 void Daemon::timerCheckIfRunning()
00461 {
00462 checkIfRunning();
00463
00464 if (mStatusTimerCount > 0 && --mStatusTimerCount <= 0)
00465 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00466 }
00467
00468
00469
00470
00471
00472 bool Daemon::checkIfRunning()
00473 {
00474 bool newstatus = isRunning();
00475 if (newstatus != mRunning)
00476 {
00477 mRunning = newstatus;
00478 int status = mRunning && !mCalendarDisabled;
00479 emit mInstance->daemonRunning(status);
00480 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00481 mStatusTimerCount = 0;
00482 if (mRunning)
00483 {
00484
00485 if (mEnableCalPending)
00486 enableCalendar(true);
00487 }
00488 }
00489 return mRunning;
00490 }
00491
00492
00493
00494
00495 void Daemon::setFastCheck()
00496 {
00497 mStatusTimer->start(500);
00498 mStatusTimerCount = 20;
00499 }
00500
00501
00502
00503
00504
00505 void Daemon::slotPreferencesChanged()
00506 {
00507 int newInterval = Preferences::daemonTrayCheckInterval();
00508 if (newInterval != mStatusTimerInterval)
00509 {
00510
00511 mStatusTimerInterval = newInterval;
00512 if (mStatusTimerCount <= 0)
00513 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00514 }
00515 }
00516
00517
00518
00519
00520 AlarmEnableAction* Daemon::createAlarmEnableAction(KActionCollection* actions, const char* name)
00521 {
00522 AlarmEnableAction* a = new AlarmEnableAction(Qt::CTRL+Qt::Key_A, actions, name);
00523 connect(a, SIGNAL(userClicked(bool)), mInstance, SLOT(setAlarmsEnabled(bool)));
00524 connect(mInstance, SIGNAL(daemonRunning(bool)), a, SLOT(setCheckedActual(bool)));
00525 return a;
00526 }
00527
00528
00529
00530
00531
00532 void Daemon::slotCalendarSaved(AlarmCalendar* cal)
00533 {
00534 if (cal == AlarmCalendar::activeCalendar())
00535 reload();
00536 }
00537
00538
00539
00540
00541
00542 int Daemon::maxTimeSinceCheck()
00543 {
00544 return DAEMON_CHECK_INTERVAL;
00545 }
00546
00547
00548
00549
00550
00551
00552 NotificationHandler::NotificationHandler()
00553 : DCOPObject(NOTIFY_DCOP_OBJECT),
00554 QObject()
00555 {
00556 kdDebug(5950) << "NotificationHandler::NotificationHandler()\n";
00557 }
00558
00559
00560
00561
00562
00563
00564 void NotificationHandler::alarmDaemonUpdate(int calendarStatus, const QString& calendarURL)
00565 {
00566 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(" << calendarStatus << ")\n";
00567 KAlarmd::CalendarStatus status = KAlarmd::CalendarStatus(calendarStatus);
00568 if (expandURL(calendarURL) != AlarmCalendar::activeCalendar()->urlString())
00569 return;
00570 bool enabled = false;
00571 switch (status)
00572 {
00573 case KAlarmd::CALENDAR_UNAVAILABLE:
00574
00575 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(CALENDAR_UNAVAILABLE)\n";
00576 break;
00577 case KAlarmd::CALENDAR_DISABLED:
00578
00579 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(DISABLE_CALENDAR)\n";
00580 break;
00581 case KAlarmd::CALENDAR_ENABLED:
00582
00583 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(ENABLE_CALENDAR)\n";
00584 enabled = true;
00585 break;
00586 default:
00587 return;
00588 }
00589 Daemon::calendarIsEnabled(enabled);
00590 }
00591
00592
00593
00594
00595 void NotificationHandler::handleEvent(const QString& url, const QString& eventId)
00596 {
00597 theApp()->handleEvent(url, eventId);
00598 }
00599
00600
00601
00602
00603
00604 void NotificationHandler::registered(bool reregister, int result)
00605 {
00606 Daemon::registrationResult(reregister, result);
00607 }
00608
00609
00610
00611
00612
00613
00614 AlarmEnableAction::AlarmEnableAction(int accel, QObject* parent, const char* name)
00615 : KToggleAction(QString::null, accel, parent, name),
00616 mInitialised(false)
00617 {
00618 setCheckedActual(false);
00619 mInitialised = true;
00620 }
00621
00622
00623
00624
00625 void AlarmEnableAction::setCheckedActual(bool running)
00626 {
00627 kdDebug(5950) << "AlarmEnableAction::setCheckedActual(" << running << ")\n";
00628 if (running != isChecked() || !mInitialised)
00629 {
00630 setText(running ? i18n("&Alarms Enabled") : i18n("Enable &Alarms"));
00631 KToggleAction::setChecked(running);
00632 emit switched(running);
00633 }
00634 }
00635
00636
00637
00638
00639
00640 void AlarmEnableAction::setChecked(bool check)
00641 {
00642 kdDebug(5950) << "AlarmEnableAction::setChecked(" << check << ")\n";
00643 if (check != isChecked())
00644 {
00645 if (check)
00646 Daemon::allowRegisterFailMsg();
00647 emit userClicked(check);
00648 }
00649 }
00650
00651
00652
00653
00654
00655
00656
00657 QString expandURL(const QString& urlString)
00658 {
00659 if (urlString.isEmpty())
00660 return QString();
00661 return KURL(urlString).url();
00662 }