00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029
00030 #include <qtimer.h>
00031 #include <qfile.h>
00032 #include <qdatetime.h>
00033
00034 #include <kapplication.h>
00035 #include <kstandarddirs.h>
00036 #include <kdebug.h>
00037 #include <klocale.h>
00038 #include <ksimpleconfig.h>
00039 #include <kprocess.h>
00040 #include <kio/netaccess.h>
00041 #include <dcopclient.h>
00042
00043 #include <libkcal/calendarlocal.h>
00044 #include <libkcal/icalformat.h>
00045
00046 #include "alarmguiiface_stub.h"
00047 #include "alarmapp.h"
00048
00049 #include "alarmdaemon.h"
00050 #include "alarmdaemon.moc"
00051
00052
00053 const int LOGIN_DELAY( 5 );
00054
00055 AlarmDaemon::AlarmDaemon(QObject *parent, const char *name)
00056 : QObject(parent, name), DCOPObject(name),
00057 mSessionStartTimer(0),
00058 mEnabled( true )
00059 {
00060 kdDebug(5900) << "AlarmDaemon::AlarmDaemon()" << endl;
00061
00062 bool splash = kapp->dcopClient()->isApplicationRegistered("ksplash");
00063 if (splash || static_cast<AlarmApp*>(kapp)->startedAtLogin())
00064 {
00065
00066
00067
00068
00069
00070 kdDebug(5900) << "AlarmDaemon::AlarmDaemon(): session start\n";
00071 mSessionStartTimer = new QTimer(this);
00072 connect(mSessionStartTimer, SIGNAL(timeout()), SLOT(checkIfSessionStarted()));
00073 mSessionStartTimer->start(splash ? 1000 : LOGIN_DELAY * 1000);
00074 }
00075
00076 readCheckInterval();
00077 readDaemonData(!!mSessionStartTimer);
00078
00079 enableAutoStart(true);
00080
00081
00082 mAlarmTimer = new QTimer(this);
00083 connect( mAlarmTimer, SIGNAL( timeout() ), SLOT( checkAlarmsSlot() ));
00084 setTimerStatus();
00085 checkAlarms();
00086 }
00087
00088 AlarmDaemon::~AlarmDaemon()
00089 {
00090 }
00091
00092
00093
00094
00095 void AlarmDaemon::quit()
00096 {
00097 kdDebug(5900) << "AlarmDaemon::quit()" << endl;
00098 exit(0);
00099 }
00100
00101 void AlarmDaemon::dumpDebug()
00102 {
00103 kdDebug(5900) << "AlarmDaemon::dumpDebug()" << endl;
00104
00105 for( ADCalendarBase *cal = mCalendars.first(); cal; cal = mCalendars.next() ) {
00106 cal->dump();
00107 }
00108
00109 kdDebug(5900) << "AlarmDaemon::dumpDebug() done" << endl;
00110 }
00111
00112
00113
00114
00115 void AlarmDaemon::enableCal_(const QString& urlString, bool enable)
00116 {
00117 kdDebug(5900) << "AlarmDaemon::enableCal_(" << urlString << ")" << endl;
00118
00119 ADCalendarBase* cal = getCalendar(urlString);
00120 if (cal)
00121 {
00122 cal->setEnabled( enable );
00123 notifyGuiCalStatus(cal);
00124 }
00125 }
00126
00127
00128
00129
00130
00131 void AlarmDaemon::addCal_(const QCString& appname, const QString& urlString, bool msgCal)
00132 {
00133 kdDebug(5900) << "AlarmDaemon::addCal_(" << urlString << "): " << (msgCal ? "KALARM" : "KORGANIZER") << endl;
00134
00135 ADCalendarBase* cal = getCalendar(urlString);
00136 if (cal)
00137 {
00138
00139 if (!cal->unregistered())
00140 return;
00141 if (cal->appName() == appname)
00142 {
00143 cal->setUnregistered( false );
00144 reloadCal_(cal);
00145 return;
00146 }
00147
00148 mCalendars.remove(cal);
00149 }
00150
00151
00152 cal = new ADCalendar(urlString, appname, (msgCal ? ADCalendar::KALARM : ADCalendar::KORGANIZER));
00153 mCalendars.append(cal);
00154
00155 addConfigCalendar(appname, cal);
00156
00157 if (cal->loaded())
00158 notifyGui((msgCal ? ADD_MSG_CALENDAR : ADD_CALENDAR), cal->urlString(), appname);
00159 kdDebug(5900) << "AlarmDaemon::addCal_(): calendar added" << endl;
00160
00161 setTimerStatus();
00162 checkAlarms(cal);
00163 }
00164
00165
00166
00167
00168
00169 void AlarmDaemon::reloadCal_(const QCString& appname, const QString& urlString, bool msgCal)
00170 {
00171 kdDebug(5900) << "AlarmDaemon::reloadCal_(" << urlString << "): " << (msgCal ? "KALARM" : "KORGANIZER") << endl;
00172
00173 if (!urlString.isEmpty())
00174 {
00175 ADCalendarBase* cal = getCalendar(urlString);
00176 if (cal)
00177 reloadCal_(cal);
00178 else
00179 {
00180
00181 if (!appname.isEmpty())
00182 addCal_(appname, urlString, msgCal);
00183 }
00184 }
00185 }
00186
00187
00188
00189
00190 void AlarmDaemon::reloadCal_(ADCalendarBase* cal)
00191 {
00192 kdDebug(5900) << "AlarmDaemon::reloadCal_(): calendar" << endl;
00193
00194 if (cal)
00195 {
00196 cal->close();
00197 if (cal->loadFile())
00198 kdDebug(5900) << "AlarmDaemon::reloadCal_(): calendar reloaded" << endl;
00199 notifyGuiCalStatus(cal);
00200 setTimerStatus();
00201 checkAlarms(cal);
00202 }
00203 }
00204
00205
00206
00207
00208
00209 void AlarmDaemon::resetMsgCal_(const QCString& appname, const QString& urlString)
00210 {
00211 kdDebug(5900) << "AlarmDaemon::resetMsgCal_(" << urlString << ")\n";
00212
00213 if (!urlString.isEmpty())
00214 {
00215 reloadCal_(appname, urlString, true);
00216 ADCalendar::clearEventsHandled(urlString);
00217 ADCalendarBase* cal = getCalendar(urlString);
00218 if (cal)
00219 checkAlarms(cal);
00220 }
00221 }
00222
00223
00224 void AlarmDaemon::removeCal_(const QString& urlString)
00225 {
00226 kdDebug(5900) << "AlarmDaemon::removeCal_(" << urlString << ")\n";
00227
00228 ADCalendarBase* cal = getCalendar(urlString);
00229 if (cal)
00230 {
00231 deleteConfigCalendar(cal);
00232 mCalendars.remove(cal);
00233 kdDebug(5900) << "AlarmDaemon::removeCal_(): calendar removed" << endl;
00234 notifyGui(DELETE_CALENDAR, urlString);
00235 setTimerStatus();
00236 }
00237 }
00238
00239
00240
00241
00242
00243 void AlarmDaemon::registerApp_(const QCString& appName, const QString& appTitle,
00244 const QCString& dcopObject, int notificationType,
00245 bool displayCalendarName, bool reregister)
00246 {
00247 kdDebug(5900) << "AlarmDaemon::registerApp_(" << appName << ", " << appTitle << ", "
00248 << dcopObject << ", " << notificationType << ", " << reregister << ")" << endl;
00249 if (!appName.isEmpty())
00250 {
00251 if (KStandardDirs::findExe(appName) == QString::null)
00252 kdError() << "AlarmDaemon::registerApp(): app not found\n";
00253 else
00254 {
00255 ClientInfo c = getClientInfo(appName);
00256 if (c.isValid())
00257 {
00258
00259 if (!reregister) {
00260
00261 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next())
00262 {
00263 if (cal->appName() == appName)
00264 cal->setUnregistered( true );
00265 }
00266 }
00267 removeClientInfo(appName);
00268 }
00269 ClientInfo cinfo(appName, appTitle, dcopObject, notificationType,
00270 displayCalendarName);
00271 mClients.append(cinfo);
00272
00273 writeConfigClient(appName, cinfo);
00274
00275 enableAutoStart(true);
00276 notifyGui(CHANGE_CLIENT);
00277 setTimerStatus();
00278 }
00279 }
00280 }
00281
00282
00283
00284
00285 void AlarmDaemon::enableAutoStart(bool on)
00286 {
00287 kdDebug(5900) << "AlarmDaemon::enableAutoStart(" << (int)on << ")\n";
00288 KConfig* config = kapp->config();
00289 config->setGroup("General");
00290 config->writeEntry("Autostart", on);
00291 config->sync();
00292 notifyGui(CHANGE_STATUS);
00293 }
00294
00295
00296
00297
00298 void AlarmDaemon::readConfig()
00299 {
00300 kdDebug(5900) << "AlarmDaemon::readConfig()\n";
00301 kapp->config()->reparseConfiguration();
00302 int oldCheckInterval = mCheckInterval;
00303 readCheckInterval();
00304 if (mCheckInterval != oldCheckInterval) {
00305 mAlarmTimer->stop();
00306 setTimerStatus();
00307 notifyGui(CHANGE_STATUS);
00308
00309
00310
00311
00312
00313 checkAlarms();
00314 }
00315 }
00316
00317
00318
00319
00320 void AlarmDaemon::readCheckInterval()
00321 {
00322 KConfig* config = kapp->config();
00323 config->setGroup("General");
00324 mCheckInterval = config->readNumEntry("CheckInterval", 1);
00325 if (mCheckInterval < 1)
00326 mCheckInterval = 1;
00327 }
00328
00329
00330
00331
00332
00333
00334 void AlarmDaemon::checkAlarmsSlot()
00335 {
00336 kdDebug(5901) << "AlarmDaemon::checkAlarmsSlot()" << endl;
00337
00338 if (mAlarmTimerSyncing)
00339 {
00340
00341 mAlarmTimer->changeInterval(mCheckInterval * 60 * 1000);
00342 mAlarmTimerSyncing = false;
00343 }
00344 checkAlarms();
00345 }
00346
00347
00348
00349
00350
00351 void AlarmDaemon::checkAlarms()
00352 {
00353 kdDebug(5901) << "AlarmDaemon::checkAlarms()" << endl;
00354
00355 if ( !mEnabled ) return;
00356
00357 for( ADCalendarBase *cal = mCalendars.first(); cal; cal = mCalendars.next() ) {
00358 checkAlarms( cal );
00359 }
00360 }
00361
00362
00363
00364
00365
00366 void AlarmDaemon::checkAlarms(const QCString& appName)
00367 {
00368 if ( !mEnabled ) return;
00369
00370 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next()) {
00371 if (cal->appName() == appName) {
00372 checkAlarms( cal );
00373 }
00374 }
00375 }
00376
00377
00378
00379
00380
00381
00382 bool AlarmDaemon::checkAlarms( ADCalendarBase* cal )
00383 {
00384 kdDebug(5901) << "AlarmDaemons::checkAlarms(" << cal->urlString() << ")" << endl;
00385
00386 if ( !mEnabled || !cal->loaded() || !cal->enabled() )
00387 return false;
00388
00389 QDateTime to = QDateTime::currentDateTime();
00390
00391 QPtrList<Event> alarmEvents;
00392 QValueList<Alarm*> alarms;
00393 QValueList<Alarm*>::ConstIterator it;
00394 switch ( cal->actionType() ) {
00395 case ADCalendar::KORGANIZER: {
00396 QDateTime from = cal->lastCheck().addSecs(1);
00397 kdDebug(5901) << " From: " << from.toString() << " To: " << to.toString() << endl;
00398
00399 bool pending = false;
00400 alarms = cal->alarms( from, to );
00401 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00402 kdDebug(5901) << "AlarmDaemon::checkAlarms(): KORGANIZER event "
00403 << (*it)->parent()->uid() << endl;
00404 if (!notifyEvent(cal, (*it)->parent()->uid()))
00405 pending = true;
00406 }
00407
00408 if (!pending) {
00409 cal->setLastCheck(to);
00410 writeConfigCalendar(cal);
00411 return true;
00412 }
00413 break;
00414 }
00415 case ADCalendar::KALARM:
00416 kdDebug(5901) << " To: " << to.toString() << endl;
00417 alarms = cal->alarmsTo( to );
00418 if (alarms.count()) {
00419 kdDebug(5901) << "Kalarm alarms=" << alarms.count() << endl;
00420 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00421 Event *event = dynamic_cast<Event *>( (*it)->parent() );
00422 if ( event ) {
00423 const QString& eventID = event->uid();
00424 kdDebug(5901) << "AlarmDaemon::checkAlarms(): KALARM event " << eventID << endl;
00425 QValueList<QDateTime> alarmtimes;
00426 checkEventAlarms(*event, alarmtimes);
00427 if (!cal->eventHandled(event, alarmtimes)) {
00428 if (notifyEvent(cal, eventID))
00429 cal->setEventHandled(event, alarmtimes);
00430 else
00431 ;
00432 }
00433 }
00434 }
00435 }
00436 break;
00437 }
00438
00439 return false;
00440 }
00441
00442
00443
00444
00445
00446 void AlarmDaemon::checkEventAlarms(const Event& event, QValueList<QDateTime>& alarmtimes)
00447 {
00448 alarmtimes.clear();
00449 const Alarm* alarm;
00450 QDateTime now = QDateTime::currentDateTime();
00451 QPtrList<Alarm> alarms = event.alarms();
00452 for (QPtrListIterator<Alarm> it(alarms); (alarm = it.current()) != 0; ++it) {
00453 alarmtimes.append((alarm->enabled() && alarm->time() <= now) ? alarm->time() : QDateTime());
00454 }
00455 }
00456
00457
00458
00459
00460
00461
00462
00463 bool AlarmDaemon::notifyEvent(ADCalendarBase* calendar, const QString& eventID)
00464 {
00465 kdDebug(5900) << "AlarmDaemon::notifyEvent(" << eventID << ")\n";
00466 if (calendar)
00467 {
00468 ClientInfo client = getClientInfo(calendar->appName());
00469 kdDebug(5900) << " appName: " << calendar->appName()
00470 << " notification type=" << client.notificationType << endl;
00471 if (!client.isValid()) {
00472 kdDebug(5900) << "AlarmDaemon::notifyEvent(): unknown client" << endl;
00473 return false;
00474 }
00475 if (client.waitForRegistration)
00476 {
00477
00478
00479
00480
00481
00482
00483 kdDebug(5900) << "AlarmDaemon::notifyEvent(): wait for session startup" << endl;
00484 return false;
00485 }
00486
00487 if (!kapp->dcopClient()->isApplicationRegistered(static_cast<const char*>(calendar->appName())))
00488 {
00489
00490 if (client.notificationType == ClientInfo::NO_START_NOTIFY
00491 || client.notificationType == ClientInfo::DCOP_SIMPLE_NOTIFY) {
00492 kdDebug(5900) << "AlarmDaemon::notifyEvent(): don't start client\n";
00493 return false;
00494 }
00495
00496
00497 KProcess p;
00498 QString cmd = locate("exe", calendar->appName());
00499 if (cmd.isEmpty()) {
00500 kdDebug(5900) << "AlarmDaemon::notifyEvent(): '"
00501 << calendar->appName() << "' not found" << endl;
00502 return true;
00503 }
00504 p << cmd;
00505 if (client.notificationType == ClientInfo::COMMAND_LINE_NOTIFY)
00506 {
00507
00508 p << "--handleEvent" << eventID << "--calendarURL" << calendar->urlString();
00509 p.start(KProcess::Block);
00510 kdDebug(5900) << "AlarmDaemon::notifyEvent(): used command line" << endl;
00511 return true;
00512 }
00513 p.start(KProcess::Block);
00514 kdDebug(5900) << "AlarmDaemon::notifyEvent(): started "
00515 << cmd << endl;
00516 }
00517
00518 if (client.notificationType == ClientInfo::DCOP_SIMPLE_NOTIFY)
00519 {
00520 Incidence *incidence = calendar->event( eventID );
00521 if (!incidence) {
00522 incidence = calendar->todo( eventID );
00523 if(!incidence) {
00524 kdDebug(5900) << "AlarmDaemon::notifyEvent(): null incidence\n";
00525 return true;
00526 }
00527 }
00528
00529 kdDebug() << "--- DCOP send: handleEvent(): " << incidence->summary() << endl;
00530
00531 CalendarLocal cal;
00532 cal.addIncidence( incidence->clone() );
00533
00534 ICalFormat format;
00535
00536 AlarmGuiIface_stub stub( calendar->appName(), client.dcopObject );
00537 stub.handleEvent( format.toString( &cal ) );
00538 if ( !stub.ok() ) {
00539 kdDebug(5900) << "AlarmDaemon::notifyEvent(): dcop send failed" << endl;
00540 return false;
00541 }
00542 }
00543 else
00544 {
00545 AlarmGuiIface_stub stub( calendar->appName(), client.dcopObject );
00546 stub.handleEvent( calendar->urlString(), eventID );
00547 if ( !stub.ok() ) {
00548 kdDebug(5900) << "AlarmDaemon::notifyEvent(): dcop send failed" << endl;
00549 return false;
00550 }
00551 }
00552 }
00553 return true;
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 void AlarmDaemon::checkIfSessionStarted()
00567 {
00568 if (!kapp->dcopClient()->isApplicationRegistered("ksplash"))
00569 {
00570
00571 kdDebug(5900) << "AlarmDaemon::checkIfSessionStarted(): startup complete\n";
00572 delete mSessionStartTimer;
00573
00574 for (ClientList::Iterator client = mClients.begin(); client != mClients.end(); ++client)
00575 {
00576 if ((*client).notificationType == ClientInfo::DCOP_NOTIFY
00577 || (*client).notificationType == ClientInfo::COMMAND_LINE_NOTIFY
00578 || kapp->dcopClient()->isApplicationRegistered(static_cast<const char*>((*client).appName))) {
00579 (*client).waitForRegistration = false;
00580 }
00581 }
00582
00583 mSessionStartTimer = 0;
00584 }
00585 }
00586
00587
00588
00589
00590 void AlarmDaemon::setTimerStatus()
00591 {
00592
00593 int nLoaded = 0;
00594 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next()) {
00595 if (cal->loaded())
00596 ++nLoaded;
00597 }
00598
00599
00600 if (!mAlarmTimer->isActive() && nLoaded)
00601 {
00602
00603
00604 int checkInterval = mCheckInterval * 60;
00605 int firstInterval = checkInterval + 1 - QTime::currentTime().second();
00606 mAlarmTimer->start(1000 * firstInterval);
00607 mAlarmTimerSyncing = (firstInterval != checkInterval);
00608 kdDebug(5900) << "Started alarm timer" << endl;
00609 }
00610 else if (mAlarmTimer->isActive() && !nLoaded)
00611 {
00612 mAlarmTimer->stop();
00613 kdDebug(5900) << "Stopped alarm timer" << endl;
00614 }
00615 }
00616
00617
00618
00619
00620
00621 void AlarmDaemon::registerGui(const QCString& appName, const QCString& dcopObject)
00622 {
00623 kdDebug(5900) << "AlarmDaemon::registerGui(" << appName << ")\n";
00624 if (!appName.isEmpty())
00625 {
00626 const GuiInfo* g = getGuiInfo(appName);
00627 if (g)
00628 mGuis.remove(appName);
00629 mGuis.insert(appName, GuiInfo(dcopObject));
00630
00631 writeConfigClientGui(appName, dcopObject);
00632
00633 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next()) {
00634 notifyGuiCalStatus(cal);
00635 }
00636 }
00637 }
00638
00639
00640
00641
00642
00643 void AlarmDaemon::notifyGuiCalStatus(const ADCalendarBase* cal)
00644 {
00645 notifyGui((cal->available() ? (cal->enabled() ? ENABLE_CALENDAR : DISABLE_CALENDAR) : CALENDAR_UNAVAILABLE),
00646 cal->urlString());
00647 }
00648
00649
00650
00651
00652 void AlarmDaemon::notifyGui(AlarmGuiChangeType change, const QString& calendarURL)
00653 {
00654 notifyGui( change, calendarURL, "" );
00655 }
00656
00657 void AlarmDaemon::notifyGui(AlarmGuiChangeType change, const QString& calendarURL, const QCString& appName)
00658 {
00659 kdDebug(5900) << "AlarmDaemon::notifyGui(" << change << ")\n";
00660
00661 for (GuiMap::ConstIterator g = mGuis.begin(); g != mGuis.end(); ++g)
00662 {
00663 QCString dcopObject = g.data().dcopObject;
00664 if (kapp->dcopClient()->isApplicationRegistered(static_cast<const char*>(g.key())))
00665 {
00666 kdDebug(5900)<<"AlarmDaemon::notifyGui() sending:" << g.key()<<" ->" << dcopObject <<endl;
00667
00668 AlarmGuiIface_stub stub( g.key(), dcopObject );
00669 stub.alarmDaemonUpdate( change, calendarURL, appName );
00670 if ( !stub.ok() )
00671 kdDebug(5900) << "AlarmDaemon::guiNotify(): dcop send failed:" << g.key() << endl;
00672 }
00673 }
00674 }
00675
00676
00677 const AlarmDaemon::GuiInfo* AlarmDaemon::getGuiInfo(const QCString& appName) const
00678 {
00679 if (!appName.isEmpty())
00680 {
00681 GuiMap::ConstIterator g = mGuis.find(appName);
00682 if (g != mGuis.end())
00683 return &g.data();
00684 }
00685 return 0;
00686 }
00687
00688 QStringList AlarmDaemon::dumpAlarms()
00689 {
00690 QDateTime start = QDateTime( QDateTime::currentDateTime().date(),
00691 QTime( 0, 0 ) );
00692 QDateTime end = start.addDays( 1 ).addSecs( -1 );
00693
00694 QStringList lst;
00695
00696 lst << QString("AlarmDeamon::dumpAlarms() from ")+start.toString()+ " to " + end.toString();
00697
00698 CalendarList cals = calendars();
00699 ADCalendarBase *cal;
00700 for( cal = cals.first(); cal; cal = cals.next() ) {
00701 lst << QString(" Cal: ") + cal->urlString();
00702 QValueList<Alarm*> alarms = cal->alarms( start, end );
00703 QValueList<Alarm*>::ConstIterator it;
00704 for( it = alarms.begin(); it != alarms.end(); ++it ) {
00705 Alarm *a = *it;
00706 lst << QString(" ") + a->parent()->summary() + " ("
00707 + a->time().toString() + ")";
00708 }
00709 }
00710 return lst;
00711 }