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 if (!appName.isEmpty())
00241 {
00242 if (KStandardDirs::findExe(appName).isNull())
00243 kdError() << "AlarmDaemon::registerApp(): app not found\n";
00244 else
00245 {
00246 ClientInfo c = getClientInfo(appName);
00247 if (c.isValid())
00248 {
00249
00250 if (!reregister) {
00251
00252 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next())
00253 {
00254 if (cal->appName() == appName)
00255 cal->setUnregistered( true );
00256 }
00257 }
00258 removeClientInfo(appName);
00259 }
00260 ClientInfo cinfo(appName, appTitle, dcopObject, notificationType,
00261 displayCalendarName);
00262 mClients.append(cinfo);
00263
00264 writeConfigClient(appName, cinfo);
00265
00266 enableAutoStart(true);
00267 notifyGui(CHANGE_CLIENT);
00268 setTimerStatus();
00269 }
00270 }
00271 }
00272
00273
00274
00275
00276 void AlarmDaemon::enableAutoStart(bool on)
00277 {
00278 kdDebug(5900) << "AlarmDaemon::enableAutoStart(" << (int)on << ")\n";
00279 KConfig* config = kapp->config();
00280 config->setGroup("General");
00281 config->writeEntry("Autostart", on);
00282 config->sync();
00283 notifyGui(CHANGE_STATUS);
00284 }
00285
00286
00287
00288
00289 void AlarmDaemon::readConfig()
00290 {
00291 kdDebug(5900) << "AlarmDaemon::readConfig()\n";
00292 kapp->config()->reparseConfiguration();
00293 int oldCheckInterval = mCheckInterval;
00294 readCheckInterval();
00295 if (mCheckInterval != oldCheckInterval) {
00296 mAlarmTimer->stop();
00297 setTimerStatus();
00298 notifyGui(CHANGE_STATUS);
00299
00300
00301
00302
00303
00304 checkAlarms();
00305 }
00306 }
00307
00308
00309
00310
00311 void AlarmDaemon::readCheckInterval()
00312 {
00313 KConfig* config = kapp->config();
00314 config->setGroup("General");
00315 mCheckInterval = config->readNumEntry("CheckInterval", 1);
00316 if (mCheckInterval < 1)
00317 mCheckInterval = 1;
00318 }
00319
00320
00321
00322
00323
00324
00325 void AlarmDaemon::checkAlarmsSlot()
00326 {
00327 kdDebug(5901) << "AlarmDaemon::checkAlarmsSlot()" << endl;
00328
00329 if (mAlarmTimerSyncing)
00330 {
00331
00332 mAlarmTimer->changeInterval(mCheckInterval * 60 * 1000);
00333 mAlarmTimerSyncing = false;
00334 }
00335 checkAlarms();
00336 }
00337
00338
00339
00340
00341
00342 void AlarmDaemon::checkAlarms()
00343 {
00344 kdDebug(5901) << "AlarmDaemon::checkAlarms()" << endl;
00345
00346 for( ADCalendarBase *cal = mCalendars.first(); cal; cal = mCalendars.next() ) {
00347 checkAlarms( cal );
00348 }
00349 }
00350
00351
00352
00353
00354
00355 void AlarmDaemon::checkAlarms(const QCString& appName)
00356 {
00357 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next()) {
00358 if (cal->appName() == appName) {
00359 checkAlarms( cal );
00360 }
00361 }
00362 }
00363
00364
00365
00366
00367
00368
00369 bool AlarmDaemon::checkAlarms( ADCalendarBase* cal )
00370 {
00371 kdDebug(5901) << "AlarmDaemons::checkAlarms(" << cal->urlString() << ")" << endl;
00372
00373 if ( !cal->loaded() || !cal->enabled() )
00374 return false;
00375
00376 QDateTime to = QDateTime::currentDateTime();
00377
00378 QPtrList<Event> alarmEvents;
00379 QValueList<Alarm*> alarms;
00380 QValueList<Alarm*>::ConstIterator it;
00381 switch ( cal->actionType() ) {
00382 case ADCalendar::KORGANIZER: {
00383 QDateTime from = cal->lastCheck().addSecs(1);
00384 kdDebug(5901) << " From: " << from.toString() << " To: " << to.toString() << endl;
00385
00386 bool pending = false;
00387 alarms = cal->alarms( from, to );
00388 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00389 kdDebug(5901) << "AlarmDaemon::checkAlarms(): KORGANIZER event "
00390 << (*it)->parent()->uid() << endl;
00391 if (!notifyEvent(cal, (*it)->parent()->uid()))
00392 pending = true;
00393 }
00394
00395 if (!pending) {
00396 cal->setLastCheck(to);
00397 writeConfigCalendar(cal);
00398 return true;
00399 }
00400 break;
00401 }
00402 case ADCalendar::KALARM:
00403 kdDebug(5901) << " To: " << to.toString() << endl;
00404 alarms = cal->alarmsTo( to );
00405 if (alarms.count()) {
00406 kdDebug(5901) << "Kalarm alarms=" << alarms.count() << endl;
00407 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00408 Event *event = dynamic_cast<Event *>( (*it)->parent() );
00409 if ( event ) {
00410 const QString& eventID = event->uid();
00411 kdDebug(5901) << "AlarmDaemon::checkAlarms(): KALARM event " << eventID << endl;
00412 QValueList<QDateTime> alarmtimes;
00413 checkEventAlarms(*event, alarmtimes);
00414 if (!cal->eventHandled(event, alarmtimes)) {
00415 if (notifyEvent(cal, eventID))
00416 cal->setEventHandled(event, alarmtimes);
00417 else
00418 ;
00419 }
00420 }
00421 }
00422 }
00423 break;
00424 }
00425
00426 return false;
00427 }
00428
00429
00430
00431
00432
00433 void AlarmDaemon::checkEventAlarms(const Event& event, QValueList<QDateTime>& alarmtimes)
00434 {
00435 alarmtimes.clear();
00436 QDateTime now = QDateTime::currentDateTime();
00437 Alarm::List alarms = event.alarms();
00438 Alarm::List::ConstIterator it;
00439 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00440 Alarm *alarm = *it;
00441 alarmtimes.append((alarm->enabled() && alarm->time() <= now) ? alarm->time() : QDateTime());
00442 }
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 bool AlarmDaemon::notifyEvent(ADCalendarBase* calendar, const QString& eventID)
00452 {
00453 kdDebug(5900) << "AlarmDaemon::notifyEvent(" << eventID << ")\n";
00454 if (calendar)
00455 {
00456 ClientInfo client = getClientInfo(calendar->appName());
00457 kdDebug(5900) << " appName: " << calendar->appName()
00458 << " notification type=" << client.notificationType << endl;
00459 if (!client.isValid()) {
00460 kdDebug(5900) << "AlarmDaemon::notifyEvent(): unknown client" << endl;
00461 return false;
00462 }
00463 if (client.waitForRegistration)
00464 {
00465
00466
00467
00468
00469
00470
00471 kdDebug(5900) << "AlarmDaemon::notifyEvent(): wait for session startup" << endl;
00472 return false;
00473 }
00474
00475 bool registered = kapp->dcopClient()->isApplicationRegistered(static_cast<const char*>(calendar->appName()));
00476 bool ready = registered;
00477 if (registered)
00478 {
00479 QCStringList objects = kapp->dcopClient()->remoteObjects(calendar->appName());
00480 if (objects.find(client.dcopObject) == objects.end())
00481 ready = false;
00482 }
00483 if (!ready)
00484 {
00485
00486
00487 if (client.notificationType == ClientInfo::NO_START_NOTIFY
00488 || client.notificationType == ClientInfo::DCOP_SIMPLE_NOTIFY) {
00489 if (registered)
00490 kdDebug(5900) << "AlarmDaemon::notifyEvent(): client not ready\n";
00491 else
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
00514
00515 p.start(KProcess::Block);
00516 kdDebug(5900) << "AlarmDaemon::notifyEvent(): started " << cmd << endl;
00517 if (!ready)
00518 {
00519 kdDebug(5900) << "AlarmDaemon::notifyEvent(): client not ready\n";
00520 return false;
00521 }
00522 }
00523
00524 if (client.notificationType == ClientInfo::DCOP_SIMPLE_NOTIFY)
00525 {
00526 Incidence *incidence = calendar->event( eventID );
00527 if (!incidence) {
00528 incidence = calendar->todo( eventID );
00529 if(!incidence) {
00530 kdDebug(5900) << "AlarmDaemon::notifyEvent(): null incidence\n";
00531 return true;
00532 }
00533 }
00534
00535 kdDebug() << "--- DCOP send: handleEvent(): " << incidence->summary() << endl;
00536
00537 CalendarLocal cal;
00538 cal.addIncidence( incidence->clone() );
00539
00540 ICalFormat format;
00541
00542 AlarmGuiIface_stub stub( calendar->appName(), client.dcopObject );
00543 stub.handleEvent( format.toString( &cal ) );
00544 if ( !stub.ok() ) {
00545 kdDebug(5900) << "AlarmDaemon::notifyEvent(): dcop send failed" << endl;
00546 return false;
00547 }
00548 }
00549 else
00550 {
00551 AlarmGuiIface_stub stub( calendar->appName(), client.dcopObject );
00552 stub.handleEvent( calendar->urlString(), eventID );
00553 if ( !stub.ok() ) {
00554 kdDebug(5900) << "AlarmDaemon::notifyEvent(): dcop send failed" << endl;
00555 return false;
00556 }
00557 }
00558 }
00559 return true;
00560 }
00561
00562
00563
00564
00565 void AlarmDaemon::setTimerStatus()
00566 {
00567
00568 int nLoaded = 0;
00569 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next()) {
00570 if (cal->loaded())
00571 ++nLoaded;
00572 }
00573
00574
00575 if (!mAlarmTimer->isActive() && nLoaded)
00576 {
00577
00578
00579 int checkInterval = mCheckInterval * 60;
00580 int firstInterval = checkInterval + 1 - QTime::currentTime().second();
00581 mAlarmTimer->start(1000 * firstInterval);
00582 mAlarmTimerSyncing = (firstInterval != checkInterval);
00583 kdDebug(5900) << "Started alarm timer" << endl;
00584 }
00585 else if (mAlarmTimer->isActive() && !nLoaded)
00586 {
00587 mAlarmTimer->stop();
00588 kdDebug(5900) << "Stopped alarm timer" << endl;
00589 }
00590 }
00591
00592
00593
00594
00595
00596 void AlarmDaemon::registerGui(const QCString& appName, const QCString& dcopObject)
00597 {
00598 kdDebug(5900) << "AlarmDaemon::registerGui(" << appName << ")\n";
00599 if (!appName.isEmpty())
00600 {
00601 const GuiInfo* g = getGuiInfo(appName);
00602 if (g)
00603 mGuis.remove(appName);
00604 mGuis.insert(appName, GuiInfo(dcopObject));
00605
00606 writeConfigClientGui(appName, dcopObject);
00607
00608 for (ADCalendarBase* cal = mCalendars.first(); cal; cal = mCalendars.next()) {
00609 notifyGuiCalStatus(cal);
00610 }
00611 }
00612 }
00613
00614
00615
00616
00617
00618 void AlarmDaemon::notifyGuiCalStatus(const ADCalendarBase* cal)
00619 {
00620 notifyGui((cal->available() ? (cal->enabled() ? ENABLE_CALENDAR : DISABLE_CALENDAR) : CALENDAR_UNAVAILABLE),
00621 cal->urlString());
00622 }
00623
00624
00625
00626
00627 void AlarmDaemon::notifyGui(AlarmGuiChangeType change, const QString& calendarURL)
00628 {
00629 notifyGui( change, calendarURL, "" );
00630 }
00631
00632 void AlarmDaemon::notifyGui(AlarmGuiChangeType change, const QString& calendarURL, const QCString& appName)
00633 {
00634 kdDebug(5900) << "AlarmDaemon::notifyGui(" << change << ")\n";
00635
00636 for (GuiMap::ConstIterator g = mGuis.begin(); g != mGuis.end(); ++g)
00637 {
00638 QCString dcopObject = g.data().dcopObject;
00639 if (kapp->dcopClient()->isApplicationRegistered(static_cast<const char*>(g.key())))
00640 {
00641 kdDebug(5900)<<"AlarmDaemon::notifyGui() sending:" << g.key()<<" ->" << dcopObject <<endl;
00642
00643 AlarmGuiIface_stub stub( g.key(), dcopObject );
00644 stub.alarmDaemonUpdate( change, calendarURL, appName );
00645 if ( !stub.ok() )
00646 kdDebug(5900) << "AlarmDaemon::guiNotify(): dcop send failed:" << g.key() << endl;
00647 }
00648 }
00649 }
00650
00651
00652 const AlarmDaemon::GuiInfo* AlarmDaemon::getGuiInfo(const QCString& appName) const
00653 {
00654 if (!appName.isEmpty())
00655 {
00656 GuiMap::ConstIterator g = mGuis.find(appName);
00657 if (g != mGuis.end())
00658 return &g.data();
00659 }
00660 return 0;
00661 }
00662
00663 QStringList AlarmDaemon::dumpAlarms()
00664 {
00665 QDateTime start = QDateTime( QDateTime::currentDateTime().date(),
00666 QTime( 0, 0 ) );
00667 QDateTime end = start.addDays( 1 ).addSecs( -1 );
00668
00669 QStringList lst;
00670
00671 lst << QString("AlarmDeamon::dumpAlarms() from ")+start.toString()+ " to " + end.toString();
00672
00673 CalendarList cals = calendars();
00674 ADCalendarBase *cal;
00675 for( cal = cals.first(); cal; cal = cals.next() ) {
00676 lst << QString(" Cal: ") + cal->urlString();
00677 QValueList<Alarm*> alarms = cal->alarms( start, end );
00678 QValueList<Alarm*>::ConstIterator it;
00679 for( it = alarms.begin(); it != alarms.end(); ++it ) {
00680 Alarm *a = *it;
00681 lst << QString(" ") + a->parent()->summary() + " ("
00682 + a->time().toString() + ")";
00683 }
00684 }
00685 return lst;
00686 }