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