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 <tqtimer.h>
00024 #include <tqiconset.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 TQString expandURL(const TQString& urlString);
00048
00049
00050
00051
00052
00053
00054
00055 class NotificationHandler : public TQObject, virtual public AlarmGuiIface
00056 {
00057 public:
00058 NotificationHandler();
00059 private:
00060
00061 void alarmDaemonUpdate(int calendarStatus, const TQString& calendarURL);
00062 void handleEvent(const TQString& calendarURL, const TQString& eventID);
00063 void registered(bool reregister, int result, int version);
00064 };
00065
00066
00067 Daemon* Daemon::mInstance = 0;
00068 NotificationHandler* Daemon::mDcopHandler = 0;
00069 TQValueList<TQString> Daemon::mQueuedEvents;
00070 TQValueList<TQString> Daemon::mSavingEvents;
00071 TQTimer* Daemon::mStartTimer = 0;
00072 TQTimer* Daemon::mRegisterTimer = 0;
00073 TQTimer* 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(), TQT_SIGNAL(calendarSaved(AlarmCalendar*)), mInstance, TQT_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(TQT_SIGNAL(preferencesChanged()), mInstance, TQT_SLOT(slotPreferencesChanged()));
00115
00116 mStatusTimer = new TQTimer(mInstance);
00117 connect(mStatusTimer, TQT_SIGNAL(timeout()), mInstance, TQT_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 TQString execStr = locate("exe", TQString::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 TQTimer(mInstance);
00148 connect(mStartTimer, TQT_SIGNAL(timeout()), mInstance, TQT_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 switch (mStatus)
00177 {
00178 case STOPPED:
00179 case RUNNING:
00180 return false;
00181 case REGISTERED:
00182 if (!reregister)
00183 return true;
00184 break;
00185 case READY:
00186 break;
00187 }
00188
00189 bool disabledIfStopped = theApp()->alarmsDisabledIfStopped();
00190 kdDebug(5950) << (reregister ? "Daemon::reregisterWith(): " : "Daemon::registerWith(): ") << (disabledIfStopped ? "NO_START" : "COMMAND_LINE") << endl;
00191 TQCString appname = kapp->aboutData()->appName();
00192 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00193 if (reregister)
00194 s.registerChange(appname, !disabledIfStopped);
00195 else
00196 s.registerApp(appname, kapp->aboutData()->programName(), TQCString(NOTIFY_DCOP_OBJECT), AlarmCalendar::activeCalendar()->urlString(), !disabledIfStopped);
00197 if (!s.ok())
00198 {
00199 kdError(5950) << "Daemon::registerWith(" << reregister << "): DCOP error" << endl;
00200 registrationResult(reregister, KAlarmd::FAILURE);
00201 return false;
00202 }
00203 mRegisterTimer = new TQTimer(mInstance);
00204 connect(mRegisterTimer, TQT_SIGNAL(timeout()), mInstance, TQT_SLOT(registerTimerExpired()));
00205 mRegisterTimer->start(REGISTER_TIMEOUT * 1000);
00206 return true;
00207 }
00208
00209
00210
00211
00212 void Daemon::registrationResult(bool reregister, int result, int version)
00213 {
00214 kdDebug(5950) << "Daemon::registrationResult(" << reregister << ") version: " << version << endl;
00215 delete mRegisterTimer;
00216 mRegisterTimer = 0;
00217 bool failed = false;
00218 TQString errmsg;
00219 if (version && version != DAEMON_VERSION_NUM)
00220 {
00221 failed = true;
00222 kdError(5950) << "Daemon::registrationResult(" << reregister << "): kalarmd reports incompatible version " << version << endl;
00223 errmsg = i18n("Cannot enable alarms.\nInstallation or configuration error: Alarm Daemon (%1) version is incompatible.")
00224 .arg(TQString::fromLatin1(DAEMON_APP_NAME));
00225 }
00226 else
00227 {
00228 switch (result)
00229 {
00230 case KAlarmd::SUCCESS:
00231 break;
00232 case KAlarmd::NOT_FOUND:
00233
00234
00235
00236 kdError(5950) << "Daemon::registrationResult(" << reregister << "): registerApp dcop call: " << kapp->aboutData()->appName() << " not found\n";
00237 KMessageBox::error(0, i18n("Alarms will be disabled if you stop KAlarm.\n"
00238 "(Installation or configuration error: %1 cannot locate %2 executable.)")
00239 .arg(TQString::fromLatin1(DAEMON_APP_NAME))
00240 .arg(kapp->aboutData()->appName()));
00241 break;
00242 case KAlarmd::FAILURE:
00243 default:
00244
00245
00246 kdError(5950) << "Daemon::registrationResult(" << reregister << "): registerApp dcop call failed -> " << result << endl;
00247 failed = true;
00248 if (!reregister)
00249 {
00250 errmsg = i18n("Cannot enable alarms:\nFailed to register with Alarm Daemon (%1)")
00251 .arg(TQString::fromLatin1(DAEMON_APP_NAME));
00252 }
00253 break;
00254 }
00255 }
00256
00257 if (failed)
00258 {
00259 if (!errmsg.isEmpty())
00260 {
00261 if (mStatus == REGISTERED)
00262 mStatus = READY;
00263 if (!mRegisterFailMsg)
00264 {
00265 mRegisterFailMsg = true;
00266 KMessageBox::error(0, errmsg);
00267 }
00268 }
00269 return;
00270 }
00271
00272 if (!reregister)
00273 {
00274
00275 mStatus = REGISTERED;
00276 mRegisterFailMsg = false;
00277 kdDebug(5950) << "Daemon::start(): daemon startup complete" << endl;
00278 }
00279 }
00280
00281
00282
00283
00284 void Daemon::checkIfStarted()
00285 {
00286 updateRegisteredStatus();
00287 bool err = false;
00288 switch (mStatus)
00289 {
00290 case STOPPED:
00291 if (--mStartTimeout > 0)
00292 return;
00293
00294
00295 err = true;
00296 break;
00297 case RUNNING:
00298 case READY:
00299 case REGISTERED:
00300 break;
00301 }
00302 delete mStartTimer;
00303 mStartTimer = 0;
00304 if (err)
00305 {
00306 kdError(5950) << "Daemon::checkIfStarted(): failed to start daemon" << endl;
00307 KMessageBox::error(0, i18n("Cannot enable alarms:\nFailed to start Alarm Daemon (%1)").arg(TQString::fromLatin1(DAEMON_APP_NAME)));
00308 }
00309 }
00310
00311
00312
00313
00314
00315 void Daemon::updateRegisteredStatus(bool timeout)
00316 {
00317 if (!kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00318 {
00319 mStatus = STOPPED;
00320 mRegisterFailMsg = false;
00321 }
00322 else
00323 {
00324 switch (mStatus)
00325 {
00326 case STOPPED:
00327
00328
00329 mStatus = RUNNING;
00330 TQTimer::singleShot(startCheckInterval, mInstance, TQT_SLOT(slotStarted()));
00331 break;
00332 case RUNNING:
00333 if (timeout)
00334 {
00335 mStatus = READY;
00336 start();
00337 }
00338 break;
00339 case READY:
00340 case REGISTERED:
00341 break;
00342 }
00343 }
00344 kdDebug(5950) << "Daemon::updateRegisteredStatus() -> " << mStatus << endl;
00345 }
00346
00347
00348
00349
00350 bool Daemon::stop()
00351 {
00352 kdDebug(5950) << "Daemon::stop()" << endl;
00353 if (kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00354 {
00355 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00356 s.quit();
00357 if (!s.ok())
00358 {
00359 kdError(5950) << "Daemon::stop(): dcop call failed" << endl;
00360 return false;
00361 }
00362 }
00363 return true;
00364 }
00365
00366
00367
00368
00369
00370
00371 bool Daemon::reset()
00372 {
00373 kdDebug(5950) << "Daemon::reset()" << endl;
00374 if (!kapp->dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
00375 return false;
00376 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00377 s.resetCalendar(TQCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString());
00378 if (!s.ok())
00379 kdError(5950) << "Daemon::reset(): resetCalendar dcop send failed" << endl;
00380 return true;
00381 }
00382
00383
00384
00385
00386 void Daemon::reload()
00387 {
00388 kdDebug(5950) << "Daemon::reload()\n";
00389 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00390 s.reloadCalendar(TQCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString());
00391 if (!s.ok())
00392 kdError(5950) << "Daemon::reload(): reloadCalendar dcop send failed" << endl;
00393 }
00394
00395
00396
00397
00398 void Daemon::enableCalendar(bool enable)
00399 {
00400 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00401 s.enableCalendar(AlarmCalendar::activeCalendar()->urlString(), enable);
00402 mEnableCalPending = false;
00403 }
00404
00405
00406
00407
00408 void Daemon::enableAutoStart(bool enable)
00409 {
00410
00411 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00412 s.enableAutoStart(enable);
00413
00414
00415
00416 KConfig adconfig(locate("config", DAEMON_APP_NAME"rc"));
00417 adconfig.setGroup(TQString::fromLatin1(DAEMON_AUTOSTART_SECTION));
00418 adconfig.writeEntry(TQString::fromLatin1(DAEMON_AUTOSTART_KEY), enable);
00419 adconfig.sync();
00420 }
00421
00422
00423
00424
00425
00426 void Daemon::notifyTimeChanged()
00427 {
00428 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00429 s.timeConfigChanged();
00430 if (!s.ok())
00431 kdError(5950) << "Daemon::timeConfigChanged(): dcop send failed" << endl;
00432 }
00433
00434
00435
00436
00437 bool Daemon::autoStart()
00438 {
00439 KConfig adconfig(locate("config", DAEMON_APP_NAME"rc"));
00440 adconfig.setGroup(TQString::fromLatin1(DAEMON_AUTOSTART_SECTION));
00441 return adconfig.readBoolEntry(TQString::fromLatin1(DAEMON_AUTOSTART_KEY), true);
00442 }
00443
00444
00445
00446
00447
00448 void Daemon::calendarIsEnabled(bool enabled)
00449 {
00450 mCalendarDisabled = !enabled;
00451 emit mInstance->daemonRunning(enabled);
00452 }
00453
00454
00455
00456
00457
00458 void Daemon::setAlarmsEnabled(bool enable)
00459 {
00460 kdDebug(5950) << "Daemon::setAlarmsEnabled(" << enable << ")\n";
00461 if (enable && !checkIfRunning())
00462 {
00463
00464 if (!start())
00465 {
00466 emit daemonRunning(false);
00467 return;
00468 }
00469 mEnableCalPending = true;
00470 setFastCheck();
00471 }
00472
00473
00474 if (checkIfRunning())
00475 enableCalendar(enable);
00476 }
00477
00478
00479
00480
00481 bool Daemon::monitoringAlarms()
00482 {
00483 bool ok = !mCalendarDisabled && isRunning();
00484 emit mInstance->daemonRunning(ok);
00485 return ok;
00486 }
00487
00488
00489
00490
00491 bool Daemon::isRunning(bool startdaemon)
00492 {
00493 static bool runState = false;
00494 updateRegisteredStatus();
00495 bool newRunState = (mStatus == READY || mStatus == REGISTERED);
00496 if (newRunState != runState)
00497 {
00498
00499 runState = newRunState;
00500 if (runState && startdaemon)
00501 start();
00502 }
00503 return runState && (mStatus == REGISTERED);
00504 }
00505
00506
00507
00508
00509 void Daemon::timerCheckIfRunning()
00510 {
00511 checkIfRunning();
00512
00513 if (mStatusTimerCount > 0 && --mStatusTimerCount <= 0)
00514 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00515 }
00516
00517
00518
00519
00520
00521 bool Daemon::checkIfRunning()
00522 {
00523 bool newstatus = isRunning();
00524 if (newstatus != mRunning)
00525 {
00526 mRunning = newstatus;
00527 int status = mRunning && !mCalendarDisabled;
00528 emit mInstance->daemonRunning(status);
00529 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00530 mStatusTimerCount = 0;
00531 if (mRunning)
00532 {
00533
00534 if (mEnableCalPending)
00535 enableCalendar(true);
00536 }
00537 }
00538 return mRunning;
00539 }
00540
00541
00542
00543
00544 void Daemon::setFastCheck()
00545 {
00546 mStatusTimer->start(500);
00547 mStatusTimerCount = 20;
00548 }
00549
00550
00551
00552
00553
00554 void Daemon::slotPreferencesChanged()
00555 {
00556 int newInterval = Preferences::daemonTrayCheckInterval();
00557 if (newInterval != mStatusTimerInterval)
00558 {
00559
00560 mStatusTimerInterval = newInterval;
00561 if (mStatusTimerCount <= 0)
00562 mStatusTimer->changeInterval(mStatusTimerInterval * 1000);
00563 }
00564 }
00565
00566
00567
00568
00569 AlarmEnableAction* Daemon::createAlarmEnableAction(KActionCollection* actions, const char* name)
00570 {
00571 AlarmEnableAction* a = new AlarmEnableAction(0, actions, name);
00572 connect(a, TQT_SIGNAL(userClicked(bool)), mInstance, TQT_SLOT(setAlarmsEnabled(bool)));
00573 connect(mInstance, TQT_SIGNAL(daemonRunning(bool)), a, TQT_SLOT(setCheckedActual(bool)));
00574 return a;
00575 }
00576
00577
00578
00579
00580
00581 void Daemon::slotCalendarSaved(AlarmCalendar* cal)
00582 {
00583 if (cal == AlarmCalendar::activeCalendar())
00584 {
00585 int n = mSavingEvents.count();
00586 if (n)
00587 {
00588
00589
00590 for (int i = 0; i < n - 1; ++i)
00591 notifyEventHandled(mSavingEvents[i], false);
00592 notifyEventHandled(mSavingEvents[n - 1], true);
00593 mSavingEvents.clear();
00594 }
00595 else
00596 reload();
00597 }
00598 }
00599
00600
00601
00602
00603 void Daemon::queueEvent(const TQString& eventId)
00604 {
00605 mQueuedEvents += eventId;
00606 }
00607
00608
00609
00610
00611
00612 void Daemon::savingEvent(const TQString& eventId)
00613 {
00614 if (mQueuedEvents.remove(eventId) > 0)
00615 mSavingEvents += eventId;
00616 }
00617
00618
00619
00620
00621
00622 void Daemon::eventHandled(const TQString& eventId, bool reloadCal)
00623 {
00624 if (mQueuedEvents.remove(eventId) > 0)
00625 notifyEventHandled(eventId, reloadCal);
00626 else if (reloadCal)
00627 reload();
00628 }
00629
00630
00631
00632
00633
00634 void Daemon::notifyEventHandled(const TQString& eventId, bool reloadCal)
00635 {
00636 kdDebug(5950) << "Daemon::notifyEventHandled(" << eventId << (reloadCal ? "): reload" : ")") << endl;
00637 AlarmDaemonIface_stub s(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT);
00638 s.eventHandled(TQCString(kapp->aboutData()->appName()), AlarmCalendar::activeCalendar()->urlString(), eventId, reloadCal);
00639 if (!s.ok())
00640 kdError(5950) << "Daemon::notifyEventHandled(): eventHandled dcop send failed" << endl;
00641 }
00642
00643
00644
00645
00646
00647 int Daemon::maxTimeSinceCheck()
00648 {
00649 return DAEMON_CHECK_INTERVAL;
00650 }
00651
00652
00653
00654
00655
00656
00657 NotificationHandler::NotificationHandler()
00658 : DCOPObject(NOTIFY_DCOP_OBJECT),
00659 TQObject()
00660 {
00661 kdDebug(5950) << "NotificationHandler::NotificationHandler()\n";
00662 }
00663
00664
00665
00666
00667
00668
00669 void NotificationHandler::alarmDaemonUpdate(int calendarStatus, const TQString& calendarURL)
00670 {
00671 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(" << calendarStatus << ")\n";
00672 KAlarmd::CalendarStatus status = KAlarmd::CalendarStatus(calendarStatus);
00673 if (expandURL(calendarURL) != AlarmCalendar::activeCalendar()->urlString())
00674 return;
00675 bool enabled = false;
00676 switch (status)
00677 {
00678 case KAlarmd::CALENDAR_UNAVAILABLE:
00679
00680 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(CALENDAR_UNAVAILABLE)\n";
00681 break;
00682 case KAlarmd::CALENDAR_DISABLED:
00683
00684 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(DISABLE_CALENDAR)\n";
00685 break;
00686 case KAlarmd::CALENDAR_ENABLED:
00687
00688 kdDebug(5950) << "NotificationHandler::alarmDaemonUpdate(ENABLE_CALENDAR)\n";
00689 enabled = true;
00690 break;
00691 default:
00692 return;
00693 }
00694 Daemon::calendarIsEnabled(enabled);
00695 }
00696
00697
00698
00699
00700 void NotificationHandler::handleEvent(const TQString& url, const TQString& eventId)
00701 {
00702 TQString id = eventId;
00703 if (id.startsWith(TQString::fromLatin1("ad:")))
00704 {
00705
00706 id = id.mid(3);
00707 Daemon::queueEvent(id);
00708 }
00709 theApp()->handleEvent(url, id);
00710 }
00711
00712
00713
00714
00715
00716 void NotificationHandler::registered(bool reregister, int result, int version)
00717 {
00718 Daemon::registrationResult(reregister, result, version);
00719 }
00720
00721
00722
00723
00724
00725
00726 AlarmEnableAction::AlarmEnableAction(int accel, TQObject* parent, const char* name)
00727 : KToggleAction(i18n("Enable &Alarms"), accel, parent, name),
00728 mInitialised(false)
00729 {
00730 setCheckedState(i18n("Disable &Alarms"));
00731 setCheckedActual(false);
00732 mInitialised = true;
00733 }
00734
00735
00736
00737
00738 void AlarmEnableAction::setCheckedActual(bool running)
00739 {
00740 kdDebug(5950) << "AlarmEnableAction::setCheckedActual(" << running << ")\n";
00741 if (running != isChecked() || !mInitialised)
00742 {
00743 KToggleAction::setChecked(running);
00744 emit switched(running);
00745 }
00746 }
00747
00748
00749
00750
00751
00752 void AlarmEnableAction::setChecked(bool check)
00753 {
00754 kdDebug(5950) << "AlarmEnableAction::setChecked(" << check << ")\n";
00755 if (check != isChecked())
00756 {
00757 if (check)
00758 Daemon::allowRegisterFailMsg();
00759 emit userClicked(check);
00760 }
00761 }
00762
00763
00764
00765
00766
00767
00768
00769 TQString expandURL(const TQString& urlString)
00770 {
00771 if (urlString.isEmpty())
00772 return TQString();
00773 return KURL(urlString).url();
00774 }