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