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
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 bool Daemon::autoStart()
00390 {
00391 KConfig adconfig(locate("config", DAEMON_APP_NAME"rc"));
00392 adconfig.setGroup(QString::fromLatin1(DAEMON_AUTOSTART_SECTION));
00393 return adconfig.readBoolEntry(QString::fromLatin1(DAEMON_AUTOSTART_KEY), true);
00394 }
00395
00396
00397
00398
00399
00400 void Daemon::calendarIsEnabled(bool enabled)
00401 {
00402 mCalendarDisabled = !enabled;
00403 emit mInstance->daemonRunning(enabled);
00404 }
00405
00406
00407
00408
00409
00410 void Daemon::setAlarmsEnabled(bool enable)
00411 {
00412 kdDebug(5950) << "Daemon::setAlarmsEnabled(" << enable << ")\n";
00413 if (enable && !checkIfRunning())
00414 {
00415
00416 if (!start())
00417 {
00418 emit daemonRunning(false);
00419 return;
00420 }
00421 mEnableCalPending = true;
00422 setFastCheck();
00423 }
00424
00425
00426 if (checkIfRunning())
00427 enableCalendar(enable);
00428 }
00429
00430
00431
00432
00433 bool Daemon::monitoringAlarms()
00434 {
00435 bool ok = !mCalendarDisabled && isRunning();
00436 emit mInstance->daemonRunning(ok);
00437 return ok;
00438 }
00439
00440
00441
00442
00443 bool Daemon::isRunning(bool startdaemon)
00444 {
00445 static bool runState = false;
00446 updateRegisteredStatus();
00447 bool newRunState = (mStatus == READY || mStatus == REGISTERED);
00448 if (newRunState != runState)
00449 {
00450
00451 runState = newRunState;
00452 if (runState && startdaemon)
00453 start();
00454 }
00455 return runState && (mStatus == REGISTERED);
00456 }
00457
00458
00459
00460
00461 void Daemon::timerCheckIfRunning()
00462 {
00463 checkIfRunning();
00464
00465 if (mStatusTimerCount > 0 && --mStatusTimerCount <= 0)
00466 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00467 }
00468
00469
00470
00471
00472
00473 bool Daemon::checkIfRunning()
00474 {
00475 bool newstatus = isRunning();
00476 if (newstatus != mRunning)
00477 {
00478 mRunning = newstatus;
00479 int status = mRunning && !mCalendarDisabled;
00480 emit mInstance->daemonRunning(status);
00481 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00482 mStatusTimerCount = 0;
00483 if (mRunning)
00484 {
00485
00486 if (mEnableCalPending)
00487 enableCalendar(true);
00488 }
00489 }
00490 return mRunning;
00491 }
00492
00493
00494
00495
00496 void Daemon::setFastCheck()
00497 {
00498 mStatusTimer->start(500);
00499 mStatusTimerCount = 20;
00500 }
00501
00502
00503
00504
00505
00506 void Daemon::slotPreferencesChanged()
00507 {
00508 int newInterval = Preferences::daemonTrayCheckInterval();
00509 if (newInterval != mStatusTimerInterval)
00510 {
00511
00512 mStatusTimerInterval = newInterval;
00513 if (mStatusTimerCount <= 0)
00514 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00515 }
00516 }
00517
00518
00519
00520
00521 AlarmEnableAction* Daemon::createAlarmEnableAction(KActionCollection* actions, const char* name)
00522 {
00523 AlarmEnableAction* a = new AlarmEnableAction(0, actions, name);
00524 connect(a, SIGNAL(userClicked(bool)), mInstance, SLOT(setAlarmsEnabled(bool)));
00525 connect(mInstance, SIGNAL(daemonRunning(bool)), a, SLOT(setCheckedActual(bool)));
00526 return a;
00527 }
00528
00529
00530
00531
00532
00533 void Daemon::slotCalendarSaved(AlarmCalendar* cal)
00534 {
00535 if (cal == AlarmCalendar::activeCalendar())
00536 {
00537 int n = mSavingEvents.count();
00538 if (n)
00539 {
00540
00541
00542 for (int i = 0; i < n - 1; ++i)
00543 notifyEventHandled(mSavingEvents[i], false);
00544 notifyEventHandled(mSavingEvents[n - 1], true);
00545 mSavingEvents.clear();
00546 }
00547 else
00548 reload();
00549 }
00550 }
00551
00552
00553
00554
00555 void Daemon::queueEvent(const QString& eventId)
00556 {
00557 mQueuedEvents += eventId;
00558 }
00559
00560
00561
00562
00563
00564 void Daemon::savingEvent(const QString& eventId)
00565 {
00566 if (mQueuedEvents.remove(eventId) > 0)
00567 mSavingEvents += eventId;
00568 }
00569
00570
00571
00572
00573
00574 void Daemon::eventHandled(const QString& eventId, bool reloadCal)
00575 {
00576 if (mQueuedEvents.remove(eventId) > 0)
00577 notifyEventHandled(eventId, reloadCal);
00578 else if (reloadCal)
00579 reload();
00580 }
00581
00582
00583
00584
00585
00586 void Daemon::notifyEventHandled(const QString& eventId, bool reloadCal)
00587 {
00588 kdDebug(5950) << "Daemon::notifyEventHandled(" << eventId << (reloadCal ? "): reload" : ")") << endl;
00589 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00590 s.eventHandled(QCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString(), eventId, reloadCal);
00591 if (!s.ok())
00592 kdError(5950) << "Daemon::notifyEventHandled(): eventHandled dcop send failed" << endl;
00593 }
00594
00595
00596
00597
00598
00599 int Daemon::maxTimeSinceCheck()
00600 {
00601 return DAEMON_CHECK_INTERVAL;
00602 }
00603
00604
00605
00606
00607
00608
00609 NotificationHandler::NotificationHandler()
00610 : DCOPObject(NOTIFY_DCOP_OBJECT),
00611 QObject()
00612 {
00613 kdDebug(5950) << "NotificationHandler::NotificationHandler()\n";
00614 }
00615
00616
00617
00618
00619
00620
00621 void NotificationHandler::alarmDaemonUpdate(int calendarStatus, const QString& calendarURL)
00622 {
00623 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(" << calendarStatus << ")\n";
00624 KAlarmd::CalendarStatus status = KAlarmd::CalendarStatus(calendarStatus);
00625 if (expandURL(calendarURL) != AlarmCalendar::activeCalendar()->urlString())
00626 return;
00627 bool enabled = false;
00628 switch (status)
00629 {
00630 case KAlarmd::CALENDAR_UNAVAILABLE:
00631
00632 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(CALENDAR_UNAVAILABLE)\n";
00633 break;
00634 case KAlarmd::CALENDAR_DISABLED:
00635
00636 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(DISABLE_CALENDAR)\n";
00637 break;
00638 case KAlarmd::CALENDAR_ENABLED:
00639
00640 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(ENABLE_CALENDAR)\n";
00641 enabled = true;
00642 break;
00643 default:
00644 return;
00645 }
00646 Daemon::calendarIsEnabled(enabled);
00647 }
00648
00649
00650
00651
00652 void NotificationHandler::handleEvent(const QString& url, const QString& eventId)
00653 {
00654 QString id = eventId;
00655 if (id.startsWith(QString::fromLatin1("ad:")))
00656 {
00657
00658 id = id.mid(3);
00659 Daemon::queueEvent(id);
00660 }
00661 theApp()->handleEvent(url, id);
00662 }
00663
00664
00665
00666
00667
00668 void NotificationHandler::registered(bool reregister, int result)
00669 {
00670 Daemon::registrationResult(reregister, result);
00671 }
00672
00673
00674
00675
00676
00677
00678 AlarmEnableAction::AlarmEnableAction(int accel, QObject* parent, const char* name)
00679 : KToggleAction(i18n("Enable &Alarms"), accel, parent, name),
00680 mInitialised(false)
00681 {
00682 setCheckedState(i18n("Disable &Alarms"));
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 KToggleAction::setChecked(running);
00696 emit switched(running);
00697 }
00698 }
00699
00700
00701
00702
00703
00704 void AlarmEnableAction::setChecked(bool check)
00705 {
00706 kdDebug(5950) << "AlarmEnableAction::setChecked(" << check << ")\n";
00707 if (check != isChecked())
00708 {
00709 if (check)
00710 Daemon::allowRegisterFailMsg();
00711 emit userClicked(check);
00712 }
00713 }
00714
00715
00716
00717
00718
00719
00720
00721 QString expandURL(const QString& urlString)
00722 {
00723 if (urlString.isEmpty())
00724 return QString();
00725 return KURL(urlString).url();
00726 }