kalarm Library API Documentation

kalarmapp.cpp

00001 /*
00002  *  kalarmapp.cpp  -  the KAlarm application object
00003  *  Program:  kalarm
00004  *  (C) 2001, 2002 by David Jarvie  software@astrojar.org.uk
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  *
00020  *  As a special exception, permission is given to link this program
00021  *  with any edition of Qt, and distribute the resulting executable,
00022  *  without including the source code for Qt in the source distribution.
00023  */
00024 
00025 #include "kalarm.h"
00026 
00027 #include <stdlib.h>
00028 #include <ctype.h>
00029 #include <iostream>
00030 
00031 #include <qfile.h>
00032 
00033 #include <kcmdlineargs.h>
00034 #include <kmessagebox.h>
00035 #include <klocale.h>
00036 #include <kstandarddirs.h>
00037 #include <kconfig.h>
00038 #include <kaboutdata.h>
00039 #include <dcopclient.h>
00040 #include <kprocess.h>
00041 #include <kfileitem.h>
00042 #include <kaction.h>
00043 #include <kstdaction.h>
00044 #include <kdebug.h>
00045 
00046 #include <kalarmd/clientinfo.h>
00047 
00048 #include <libkcal/calformat.h>
00049 
00050 #include "alarmcalendar.h"
00051 #include "mainwindow.h"
00052 #include "messagewin.h"
00053 #include "daemongui.h"
00054 #include "traywindow.h"
00055 #include "prefsettings.h"
00056 #include "prefdlg.h"
00057 #include "kalarmapp.moc"
00058 
00059 #include <netwm.h>
00060 
00061 extern QCString execArguments;
00062 
00063 #define     DAEMON_APP_NAME_DEF    "kalarmd"
00064 const char* DCOP_OBJECT_NAME     = "display";
00065 const char* GUI_DCOP_OBJECT_NAME = "tray";
00066 const char* DAEMON_APP_NAME      = DAEMON_APP_NAME_DEF;
00067 const char* DAEMON_DCOP_OBJECT   = "ad";
00068 
00069 int         marginKDE2 = 0;
00070 
00071 static bool convWakeTime(const QCString timeParam, QDateTime&, bool& noTime);
00072 
00073 KAlarmApp*  KAlarmApp::theInstance = 0L;
00074 int         KAlarmApp::activeCount = 0;
00075 
00076 
00077 /******************************************************************************
00078 * Construct the application.
00079 */
00080 KAlarmApp::KAlarmApp()
00081         : KUniqueApplication(),
00082           mDcopHandler(0L),
00083           mDaemonGuiHandler(0L),
00084           mTrayWindow(0L),
00085           mCalendar(new AlarmCalendar),
00086           mSettings(new Settings(0L)),
00087           mDaemonCheckInterval(0),
00088           mDaemonRegistered(false),
00089           mDaemonRunning(false),
00090           mSessionClosingDown(false)
00091 {
00092 #if KDE_VERSION < 290
00093         marginKDE2 = KDialog::marginHint();
00094 #endif
00095         mSettings->loadSettings();
00096         connect(mSettings, SIGNAL(settingsChanged()), this, SLOT(slotSettingsChanged()));
00097         CalFormat::setApplication(aboutData()->programName(),
00098                                   QString::fromLatin1("-//K Desktop Environment//NONSGML %1 " KALARM_VERSION "//EN")
00099                                                .arg(aboutData()->programName()));
00100         readDaemonCheckInterval();
00101 
00102         // Check if it's a KDE desktop, i.e. with window manager name "KWin"
00103         NETRootInfo nri(qt_xdisplay(), NET::SupportingWMCheck);
00104         const char* wmname = nri.wmName();
00105         mKDEDesktop = wmname && !strcmp(wmname, "KWin");
00106 
00107         mOldRunInSystemTray     = mKDEDesktop && mSettings->runInSystemTray();
00108         mDisableAlarmsIfStopped = mOldRunInSystemTray && mSettings->disableAlarmsIfStopped();
00109         mStartOfDay             = mSettings->startOfDay();
00110         if (mSettings->startOfDayChanged())
00111                 mStartOfDay.setHMS(100,0,0);    // start of day time has changed: flag it as invalid
00112 
00113         // Set up actions used by more than one menu
00114         KActionCollection* actions = new KActionCollection(this);
00115         mActionAlarmEnable   = new ActionAlarmsEnabled(Qt::CTRL+Qt::Key_E, this, SLOT(toggleAlarmsEnabled()), actions, "alarmenable");
00116         mActionPrefs         = KStdAction::preferences(this, SLOT(slotPreferences()), actions);
00117 #if KDE_VERSION >= 308
00118         mActionDaemonControl = new KAction(i18n("Control Alarm &Daemon..."), mActionPrefs->iconSet(),
00119 #else
00120         mActionDaemonControl = new KAction(i18n("Configure Alarm &Daemon..."), mActionPrefs->iconSet(),
00121 #endif
00122                                            0, this, SLOT(slotDaemonControl()), actions, "controldaemon");
00123 }
00124 
00125 /******************************************************************************
00126 */
00127 KAlarmApp::~KAlarmApp()
00128 {
00129         mCalendar->close();
00130 }
00131 
00132 /******************************************************************************
00133 * Return the one and only KAlarmApp instance.
00134 * If it doesn't already exist, it is created first.
00135 */
00136 KAlarmApp* KAlarmApp::getInstance()
00137 {
00138         if (!theInstance)
00139                 theInstance = new KAlarmApp;
00140         return theInstance;
00141 }
00142 
00143 /******************************************************************************
00144 * Restore the saved session if required.
00145 */
00146 bool KAlarmApp::restoreSession()
00147 {
00148         if (!isRestored())
00149                 return false;
00150 
00151         // Process is being restored by session management.
00152         kdDebug(5950) << "KAlarmApp::restoreSession(): Restoring\n";
00153         ++activeCount;
00154         int exitCode = !initCheck(true);     // open the calendar file (needed for main windows)
00155         KAlarmMainWindow* trayParent = 0L;
00156         for (int i = 1;  KMainWindow::canBeRestored(i);  ++i)
00157         {
00158                 QString type = KMainWindow::classNameOfToplevel(i);
00159                 if (type == QString::fromLatin1("KAlarmMainWindow"))
00160                 {
00161                         KAlarmMainWindow* win = new KAlarmMainWindow(true);
00162                         win->restore(i, false);
00163                         if (win->hiddenTrayParent())
00164                                 trayParent = win;
00165                         else
00166                                 win->show();
00167                 }
00168                 else if (type == QString::fromLatin1("MessageWin"))
00169                 {
00170                         MessageWin* win = new MessageWin;
00171                         win->restore(i, false);
00172                         if (win->errorMessage())
00173                                 delete win;
00174                         else
00175                                 win->show();
00176                 }
00177         }
00178         initCheck();           // register with the alarm daemon
00179 
00180         // Display the system tray icon if it is configured to be autostarted,
00181         // or if we're in run-in-system-tray mode.
00182         if (mSettings->autostartTrayIcon()
00183         ||  KAlarmMainWindow::count()  &&  runInSystemTray())
00184                 displayTrayIcon(true, trayParent);
00185 
00186         --activeCount;
00187         quitIf(exitCode);           // quit if no windows are open
00188         return true;
00189 }
00190 
00191 /******************************************************************************
00192 * Called for a KUniqueApplication when a new instance of the application is
00193 * started.
00194 */
00195 int KAlarmApp::newInstance()
00196 {
00197         kdDebug(5950)<<"KAlarmApp::newInstance()\n";
00198         ++activeCount;
00199         int exitCode = 0;               // default = success
00200         static bool firstInstance = true;
00201         bool skip = (firstInstance && isRestored());
00202         firstInstance = false;
00203         if (!skip)
00204         {
00205                 QString usage;
00206                 KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
00207 
00208                 // Use a 'do' loop which is executed only once to allow easy error exits.
00209                 // Errors use 'break' to skip to the end of the function.
00210 
00211                 // Note that DCOP handling is only set up once the command line parameters
00212                 // have been checked, since we mustn't register with the alarm daemon only
00213                 // to quit immediately afterwards.
00214                 do
00215                 {
00216                         if (args->isSet("stop"))
00217                         {
00218                                 // Stop the alarm daemon
00219                                 kdDebug(5950)<<"KAlarmApp::newInstance(): stop\n";
00220                                 args->clear();      // free up memory
00221                                 if (!stopDaemon())
00222                                 {
00223                                         exitCode = 1;
00224                                         break;
00225                                 }
00226                         }
00227                         else
00228                         if (args->isSet("reset"))
00229                         {
00230                                 // Reset the alarm daemon
00231                                 kdDebug(5950)<<"KAlarmApp::newInstance(): reset\n";
00232                                 args->clear();      // free up memory
00233                                 setUpDcop();        // we're now ready to handle DCOP calls, so set up handlers
00234                                 resetDaemon();
00235                         }
00236                         else
00237                         if (args->isSet("tray"))
00238                         {
00239                                 // Display only the system tray icon
00240                                 kdDebug(5950)<<"KAlarmApp::newInstance(): tray\n";
00241                                 args->clear();      // free up memory
00242                                 setUpDcop();        // we're now ready to handle DCOP calls, so set up handlers
00243                                 if (!mKDEDesktop
00244                                 ||  !initCheck())   // open the calendar, register with daemon
00245                                 {
00246                                         exitCode = 1;
00247                                         break;
00248                                 }
00249                                 if (runInSystemTray()  &&  !KAlarmMainWindow::count())
00250                                         new KAlarmMainWindow;
00251                                 if (!displayTrayIcon(true))
00252                                 {
00253                                         exitCode = 1;
00254                                         break;
00255                                 }
00256                         }
00257                         else
00258                         if (args->isSet("handleEvent")  ||  args->isSet("triggerEvent")  ||  args->isSet("cancelEvent")  ||  args->isSet("calendarURL")
00259 /* superseded */        ||  args->isSet("displayEvent"))  // kept for compatibility
00260                         {
00261                                 // Display or delete the event with the specified event ID
00262                                 kdDebug(5950)<<"KAlarmApp::newInstance(): handle event\n";
00263                                 EventFunc function = EVENT_HANDLE;
00264                                 int count = 0;
00265                                 const char* option = 0;
00266                                 if (args->isSet("handleEvent"))   { function = EVENT_HANDLE;  option = "handleEvent";  ++count; }
00267 /* superseded */                if (args->isSet("displayEvent"))  { function = EVENT_TRIGGER;  option = "displayEvent";  ++count; }
00268                                 if (args->isSet("triggerEvent"))  { function = EVENT_TRIGGER;  option = "triggerEvent";  ++count; }
00269                                 if (args->isSet("cancelEvent"))   { function = EVENT_CANCEL;  option = "cancelEvent";  ++count; }
00270                                 if (!count)
00271                                 {
00272                                         usage = i18n("%1 requires %2, %3 or %4").arg(QString::fromLatin1("--calendarURL")).arg(QString::fromLatin1("--handleEvent")).arg(QString::fromLatin1("--triggerEvent")).arg(QString::fromLatin1("--cancelEvent"));
00273                                         break;
00274                                 }
00275                                 if (count > 1)
00276                                 {
00277                                         usage = i18n("%1, %2, %3 mutually exclusive").arg(QString::fromLatin1("--handleEvent")).arg(QString::fromLatin1("--triggerEvent")).arg(QString::fromLatin1("--cancelEvent"));
00278                                         break;
00279                                 }
00280                                 if (!initCheck(true))   // open the calendar, don't register with daemon yet
00281                                 {
00282                                         exitCode = 1;
00283                                         break;
00284                                 }
00285                                 if (args->isSet("calendarURL"))
00286                                 {
00287                                         QString calendarUrl = args->getOption("calendarURL");
00288                                         if (KURL(calendarUrl).url() != mCalendar->urlString())
00289                                         {
00290                                                 usage = i18n("%1: wrong calendar file").arg(QString::fromLatin1("--calendarURL"));
00291                                                 break;
00292                                         }
00293                                 }
00294                                 QString eventID = args->getOption(option);
00295                                 args->clear();      // free up memory
00296                                 setUpDcop();        // we're now ready to handle DCOP calls, so set up handlers
00297                                 if (!handleEvent(eventID, function))
00298                                 {
00299                                         exitCode = 1;
00300                                         break;
00301                                 }
00302                         }
00303                         else
00304                         if (args->isSet("file")  ||  args->isSet("exec")  ||  args->count())
00305                         {
00306                                 // Display a message or file, or execute a command
00307                                 KAlarmAlarm::Type type = KAlarmAlarm::MESSAGE;
00308                                 QCString alMessage;
00309                                 if (args->isSet("file"))
00310                                 {
00311                                         kdDebug(5950)<<"KAlarmApp::newInstance(): file\n";
00312                                         if (args->isSet("exec"))
00313                                         {
00314                                                 usage = i18n("%1 incompatible with %2").arg(QString::fromLatin1("--exec")).arg(QString::fromLatin1("--file"));
00315                                                 break;
00316                                         }
00317                                         if (args->count())
00318                                         {
00319                                                 usage = i18n("message incompatible with %1").arg(QString::fromLatin1("--file"));
00320                                                 break;
00321                                         }
00322                                         alMessage = args->getOption("file");
00323                                         type = KAlarmAlarm::FILE;
00324                                 }
00325                                 else if (args->isSet("exec"))
00326                                 {
00327                                         kdDebug(5950)<<"KAlarmApp::newInstance(): exec\n";
00328                                         alMessage = execArguments;
00329                                         type = KAlarmAlarm::COMMAND;
00330                                 }
00331 #ifdef KALARM_EMAIL
00332                                 else if (args->isSet("mail"))
00333                                 {
00334                                         kdDebug(5950)<<"KAlarmApp::newInstance(): mail\n";
00335                                         if (args->isSet("subject"))
00336                                                 alSubject = args->getOption("subject");
00337                                         alAddrs = args->getOptionList("mail");
00338                                         for (QCStringList::iterator i = alAddrs.begin();  i != alAddrs.end();  ++i)
00339                                         {
00340                                                 QString addr = QString::fromLatin1(*i);
00341                                                 if (!KAMail::checkEmailAddress(addr))
00342                                                         USAGE(i18n("%1: invalid email address").arg(QString::fromLatin1("--mail")))
00343                                                 alAddresses += addr;
00344                                         }
00345                                         alMessage = args->arg(0);
00346                                         type = KAlarmAlarm::EMAIL;
00347                                 }
00348 #endif
00349                                 else
00350                                 {
00351                                         kdDebug(5950)<<"KAlarmApp::newInstance(): message\n";
00352                                         alMessage = args->arg(0);
00353                                 }
00354 
00355                                 bool      alarmNoTime = false;
00356                                 QDateTime alarmTime, endTime;
00357                                 QColor    bgColour = mSettings->defaultBgColour();
00358                                 int       repeatCount = 0;
00359                                 int       repeatInterval = 0;
00360                                 KAlarmEvent::RecurType recurType = KAlarmEvent::NO_RECUR;
00361                                 if (args->isSet("color"))
00362                                 {
00363                                         // Colour is specified
00364                                         QCString colourText = args->getOption("color");
00365                                         if (static_cast<const char*>(colourText)[0] == '0'
00366                                         &&  tolower(static_cast<const char*>(colourText)[1]) == 'x')
00367                                                 colourText.replace(0, 2, "#");
00368                                         bgColour.setNamedColor(colourText);
00369                                         if (!bgColour.isValid())
00370                                         {
00371                                                 usage = i18n("Invalid %1 parameter").arg(QString::fromLatin1("--color"));
00372                                                 break;
00373                                         }
00374                                 }
00375 
00376                                 if (args->isSet("time"))
00377                                 {
00378                                         QCString dateTime = args->getOption("time");
00379                                         if (!convWakeTime(dateTime, alarmTime, alarmNoTime))
00380                                         {
00381                                                 usage = i18n("Invalid %1 parameter").arg(QString::fromLatin1("--time"));
00382                                                 break;
00383                                         }
00384                                 }
00385                                 else
00386                                         alarmTime = QDateTime::currentDateTime();
00387 
00388                                 if (args->isSet("interval"))
00389                                 {
00390                                         // Repeat count is specified
00391                                         if (args->isSet("login"))
00392                                         {
00393                                                 usage = i18n("%1 incompatible with %2").arg(QString::fromLatin1("--login")).arg(QString::fromLatin1("--interval"));
00394                                                 break;
00395                                         }
00396                                         if (!args->isSet("repeat")  &&  !args->isSet("until"))
00397                                         {
00398                                                 usage = i18n("%1 requires %2 or %3").arg(QString::fromLatin1("--interval")).arg(QString::fromLatin1("--repeat")).arg(QString::fromLatin1("--until"));
00399                                                 break;
00400                                         }
00401                                         bool ok;
00402                                         if (args->isSet("repeat"))
00403                                         {
00404                                                 repeatCount = args->getOption("repeat").toInt(&ok);
00405                                                 if (!ok || !repeatCount || repeatCount < -1)
00406                                                 {
00407                                                         usage = i18n("Invalid %1 parameter").arg(QString::fromLatin1("--repeat"));
00408                                                         break;
00409                                                 }
00410                                         }
00411                                         else
00412                                         {
00413                                                 QCString dateTime = args->getOption("until");
00414                                                 if (!convWakeTime(dateTime, endTime, alarmNoTime))
00415                                                 {
00416                                                         usage = i18n("Invalid %1 parameter").arg(QString::fromLatin1("--until"));
00417                                                         break;
00418                                                 }
00419                                                 if (endTime < alarmTime)
00420                                                 {
00421                                                         usage = i18n("%1 earlier than %2").arg(QString::fromLatin1("--until")).arg(QString::fromLatin1("--time"));
00422                                                         break;
00423                                                 }
00424                                         }
00425 
00426                                         // Get the recurrence interval
00427                                         ok = true;
00428                                         uint interval = 0;
00429                                         QCString optval = args->getOption("interval");
00430                                         uint length = optval.length();
00431                                         switch (optval[length - 1])
00432                                         {
00433                                                 case 'Y':
00434                                                         recurType = KAlarmEvent::ANNUAL_DATE;
00435                                                         optval = optval.left(length - 1);
00436                                                         break;
00437                                                 case 'W':
00438                                                         recurType = KAlarmEvent::WEEKLY;
00439                                                         optval = optval.left(length - 1);
00440                                                         break;
00441                                                 case 'D':
00442                                                         recurType = KAlarmEvent::DAILY;
00443                                                         optval = optval.left(length - 1);
00444                                                         break;
00445                                                 case 'M':
00446                                                 {
00447                                                         int i = optval.find('H');
00448                                                         if (i < 0)
00449                                                                 recurType = KAlarmEvent::MONTHLY_DAY;
00450                                                         else
00451                                                         {
00452                                                                 recurType = KAlarmEvent::MINUTELY;
00453                                                                 interval = optval.left(i).toUInt(&ok) * 60;
00454                                                                 optval = optval.right(length - i - 1);
00455                                                         }
00456                                                         break;
00457                                                 }
00458                                                 default:       // should be a digit
00459                                                         recurType = KAlarmEvent::MINUTELY;
00460                                                         break;
00461                                         }
00462                                         if (ok)
00463                                                 interval += optval.toUInt(&ok);
00464                                         repeatInterval = static_cast<int>(interval);
00465                                         if (!ok || repeatInterval < 0)
00466                                         {
00467                                                 usage = i18n("Invalid %1 parameter").arg(QString::fromLatin1("--interval"));
00468                                                 break;
00469                                         }
00470                                 }
00471                                 else
00472                                 {
00473                                         if (args->isSet("repeat"))
00474                                         {
00475                                                 usage = i18n("%1 requires %2").arg(QString::fromLatin1("--repeat")).arg(QString::fromLatin1("--interval"));
00476                                                 break;
00477                                         }
00478                                         if (args->isSet("until"))
00479                                         {
00480                                                 usage = i18n("%1 requires %2").arg(QString::fromLatin1("--until")).arg(QString::fromLatin1("--interval"));
00481                                                 break;
00482                                         }
00483                                 }
00484 
00485                                 QCString audioFile;
00486                                 if (args->isSet("sound"))
00487                                 {
00488                                         // Play a sound with the alarm
00489                                         if (args->isSet("beep"))
00490                                         {
00491                                                 usage = i18n("%1 incompatible with %2").arg(QString::fromLatin1("--beep")).arg(QString::fromLatin1("--sound"));
00492                                                 break;
00493                                         }
00494                                         audioFile = args->getOption("sound");
00495                                 }
00496 
00497                                 int flags = 0;
00498                                 if (args->isSet("ack-confirm"))
00499                                         flags |= KAlarmEvent::CONFIRM_ACK;
00500                                 if (args->isSet("beep"))
00501                                         flags |= KAlarmEvent::BEEP;
00502                                 if (args->isSet("late-cancel"))
00503                                         flags |= KAlarmEvent::LATE_CANCEL;
00504                                 if (args->isSet("login"))
00505                                         flags |= KAlarmEvent::REPEAT_AT_LOGIN;
00506                                 args->clear();      // free up memory
00507 
00508                                 // Display or schedule the event
00509                                 setUpDcop();        // we're now ready to handle DCOP calls, so set up handlers
00510                                 if (!scheduleEvent(alMessage, alarmTime, bgColour, flags, audioFile, type, recurType,
00511                                                    repeatInterval, repeatCount, endTime))
00512                                 {
00513                                         exitCode = 1;
00514                                         break;
00515                                 }
00516                         }
00517                         else
00518                         {
00519                                 // No arguments - run interactively & display the main window
00520                                 kdDebug(5950)<<"KAlarmApp::newInstance(): interactive\n";
00521                                 if (args->isSet("ack-confirm"))
00522                                         usage += QString::fromLatin1("--ack-confirm ");
00523                                 if (args->isSet("beep"))
00524                                         usage += QString::fromLatin1("--beep ");
00525                                 if (args->isSet("color"))
00526                                         usage += QString::fromLatin1("--color ");
00527                                 if (args->isSet("late-cancel"))
00528                                         usage += QString::fromLatin1("--late-cancel ");
00529                                 if (args->isSet("login"))
00530                                         usage += QString::fromLatin1("--login ");
00531                                 if (args->isSet("sound"))
00532                                         usage += QString::fromLatin1("--sound ");
00533                                 if (args->isSet("time"))
00534                                         usage += QString::fromLatin1("--time ");
00535                                 if (!usage.isEmpty())
00536                                 {
00537                                         usage += i18n(": option(s) only valid with a message/%1/%2").arg(QString::fromLatin1("--file")).arg(QString::fromLatin1("--exec"));
00538                                         break;
00539                                 }
00540 
00541                                 args->clear();      // free up memory
00542                                 setUpDcop();        // we're now ready to handle DCOP calls, so set up handlers
00543                                 if (!initCheck())
00544                                 {
00545                                         exitCode = 1;
00546                                         break;
00547                                 }
00548 
00549                                 (new KAlarmMainWindow)->show();
00550                         }
00551                 } while (0);    // only execute once
00552 
00553                 if (!usage.isEmpty())
00554                 {
00555                         // Note: we can't use args->usage() since that also quits any other
00556                         // running 'instances' of the program.
00557                         std::cerr << usage << i18n("\nUse --help to get a list of available command line options.\n");
00558                         exitCode = 1;
00559                 }
00560         }
00561         --activeCount;
00562 
00563         // Quit the application if this was the last/only running "instance" of the program.
00564         // Executing 'return' doesn't work very well since the program continues to
00565         // run if no windows were created.
00566         quitIf(exitCode);
00567         return exitCode;
00568 }
00569 
00570 /******************************************************************************
00571 * Quit the program if there are no more "instances" running.
00572 */
00573 void KAlarmApp::quitIf(int exitCode)
00574 {
00575         if (activeCount <= 0  &&  !KAlarmMainWindow::count()  &&  !MessageWin::instanceCount()  &&  !mTrayWindow)
00576         {
00577                 /* This was the last/only running "instance" of the program, so exit completely.
00578                  * First, change the name which we are registered with at the DCOP server. This is
00579                  * to ensure that the alarm daemon immediately sees us as not running. It prevents
00580                  * the following situation which otherwise has been observed:
00581                  *
00582                  * If KAlarm is not running and, for instance, it has registered more than one
00583                  * calendar at some time in the past, when the daemon checks pending alarms, it
00584                  * starts KAlarm to notify us of the first event. If this is for a different
00585                  * calendar from what KAlarm expects, we exit. But without DCOP re-registration,
00586                  * when the daemon then notifies us of the next event (from the correct calendar),
00587                  * it will still see KAlarm as registered with DCOP and therefore tells us via a
00588                  * DCOP call. The call of course never reaches KAlarm but the daemon sees it as
00589                  * successful. The result is that the alarm is never seen.
00590                  */
00591                 kdDebug(5950) << "KAlarmApp::quitIf(" << exitCode << "): quitting" << endl;
00592                 dcopClient()->registerAs(QCString(aboutData()->appName()) + "-quitting");
00593                 exit(exitCode);
00594         }
00595 }
00596 
00597 /******************************************************************************
00598 * Called when the session manager is about to close down the application.
00599 */
00600 void KAlarmApp::commitData(QSessionManager& sm)
00601 {
00602         mSessionClosingDown = true;
00603         KUniqueApplication::commitData(sm);
00604         mSessionClosingDown = false;         // reset in case shutdown is cancelled
00605 }
00606 
00607 /******************************************************************************
00608 * Called when the system tray main window is closed.
00609 */
00610 void KAlarmApp::removeWindow(TrayWindow*)
00611 {
00612         mTrayWindow = 0L;
00613         quitIf();
00614 }
00615 
00616 /******************************************************************************
00617 *  Display or close the system tray icon.
00618 */
00619 bool KAlarmApp::displayTrayIcon(bool show, KAlarmMainWindow* parent)
00620 {
00621         if (show)
00622         {
00623                 if (!mTrayWindow)
00624                 {
00625                         if (!mKDEDesktop)
00626                                 return false;
00627                         mTrayWindow = new TrayWindow(parent ? parent : KAlarmMainWindow::firstWindow());
00628                         connect(mTrayWindow, SIGNAL(deleted()), this, SIGNAL(trayIconToggled()));
00629                         mTrayWindow->show();
00630                         emit trayIconToggled();
00631                 }
00632         }
00633         else if (mTrayWindow)
00634                 delete mTrayWindow;
00635         return true;
00636 }
00637 
00638 /******************************************************************************
00639 *  Display a main window.
00640 */
00641 void KAlarmApp::displayMainWindow()
00642 {
00643         KAlarmMainWindow* win = KAlarmMainWindow::firstWindow();
00644         if (!win)
00645         {
00646                 if (initCheck())
00647                         (new KAlarmMainWindow)->show();
00648         }
00649         else
00650         {
00651                 // There is already a main window, so make it the active window
00652                 if (!win->isVisible())
00653                 {
00654                         win->hide();        // in case it's on a different desktop
00655                         win->showNormal();
00656                 }
00657                 win->raise();
00658                 win->setActiveWindow();
00659         }
00660 }
00661 
00662 KAlarmMainWindow* KAlarmApp::trayMainWindow() const
00663 {
00664         return mTrayWindow ? mTrayWindow->assocMainWindow() : 0L;
00665 }
00666 
00667 /******************************************************************************
00668 * Called when the Alarms Enabled action is selected.
00669 * The alarm daemon is told to stop or start monitoring the calendar file as
00670 * appropriate.
00671 */
00672 void KAlarmApp::toggleAlarmsEnabled()
00673 {
00674         if (mDaemonGuiHandler)
00675                 mDaemonGuiHandler->setAlarmsEnabled(!mActionAlarmEnable->alarmsEnabled());
00676 }
00677 
00678 /******************************************************************************
00679 *  Called when a Preferences menu item is selected.
00680 */
00681 void KAlarmApp::slotPreferences()
00682 {
00683         (new KAlarmPrefDlg(mSettings))->exec();
00684 }
00685 
00686 /******************************************************************************
00687 * Called when a Control Alarm Daemon menu item is selected.
00688 * Displays the alarm daemon control dialog.
00689 */
00690 void KAlarmApp::slotDaemonControl()
00691 {
00692         KProcess proc;
00693         proc << locate("exe", QString::fromLatin1("kcmshell"));
00694 #if KDE_VERSION >= 308
00695         proc << QString::fromLatin1("kcmkded");
00696 #else
00697         proc << QString::fromLatin1("alarmdaemonctrl");
00698 #endif
00699         proc.start(KProcess::DontCare);
00700 }
00701 
00702 /******************************************************************************
00703 *  Called when KAlarm settings have changed.
00704 */
00705 void KAlarmApp::slotSettingsChanged()
00706 {
00707         bool newRunInSysTray = mSettings->runInSystemTray()  &&  mKDEDesktop;
00708         if (newRunInSysTray != mOldRunInSystemTray)
00709         {
00710                 // The system tray run mode has changed
00711                 ++activeCount;          // prevent the application from quitting
00712                 KAlarmMainWindow* win = mTrayWindow ? mTrayWindow->assocMainWindow() : 0L;
00713                 delete mTrayWindow;     // remove the system tray icon if it is currently shown
00714                 mTrayWindow = 0L;
00715                 mOldRunInSystemTray = newRunInSysTray;
00716                 if (newRunInSysTray)
00717                 {
00718                         if (!KAlarmMainWindow::count())
00719                                 new KAlarmMainWindow;
00720                         displayTrayIcon(true);
00721                 }
00722                 else
00723                 {
00724                         if (win  &&  win->isHidden())
00725                                 delete win;
00726                         displayTrayIcon(true);
00727                 }
00728                 --activeCount;
00729         }
00730 
00731         bool newDisableIfStopped = mKDEDesktop && mSettings->runInSystemTray() && mSettings->disableAlarmsIfStopped();
00732         if (newDisableIfStopped != mDisableAlarmsIfStopped)
00733         {
00734                 mDisableAlarmsIfStopped = newDisableIfStopped;    // N.B. this setting is used by registerWithDaemon()
00735                 registerWithDaemon(true);     // re-register with the alarm daemon
00736         }
00737 
00738         // Change alarm times for date-only alarms if the start of day time has changed
00739         if (mSettings->startOfDay() != mStartOfDay)
00740                 changeStartOfDay();
00741 }
00742 
00743 /******************************************************************************
00744 *  Change alarm times for date-only alarms after the start of day time has changed.
00745 */
00746 void KAlarmApp::changeStartOfDay()
00747 {
00748         if (KAlarmEvent::adjustStartOfDay(mCalendar->events()))
00749         {
00750                 mCalendar->save();
00751                 reloadDaemon();                      // tell the daemon to reread the calendar file
00752         }
00753         mSettings->updateStartOfDayCheck();  // now that calendar is updated, set OK flag in config file
00754         mStartOfDay = mSettings->startOfDay();
00755 }
00756 
00757 /******************************************************************************
00758 *  Return whether the program is configured to be running in the system tray.
00759 */
00760 bool KAlarmApp::runInSystemTray() const
00761 {
00762         return mSettings->runInSystemTray()  &&  mKDEDesktop;
00763 }
00764 
00765 /******************************************************************************
00766 * Called to schedule a new alarm, either in response to a DCOP notification or
00767 * to command line options.
00768 * Reply = true unless there was a parameter error or an error opening calendar file.
00769 */
00770 bool KAlarmApp::scheduleEvent(const QString& message, const QDateTime& dateTime, const QColor& bg,
00771                               int flags, const QString& audioFile, KAlarmAlarm::Type type,
00772                               KAlarmEvent::RecurType recurType, int repeatInterval, int repeatCount,
00773                               const QDateTime& endTime)
00774         {
00775         kdDebug(5950) << "KAlarmApp::scheduleEvent(): " << message << endl;
00776         if (!dateTime.isValid())
00777                 return false;
00778         QDateTime now = QDateTime::currentDateTime();
00779         if ((flags & KAlarmEvent::LATE_CANCEL)  &&  dateTime < now.addSecs(-maxLateness()))
00780                 return true;               // alarm time was already expired too long ago
00781         QDateTime alarmTime = dateTime;
00782         // Round down to the nearest minute to avoid scheduling being messed up
00783         alarmTime.setTime(QTime(alarmTime.time().hour(), alarmTime.time().minute(), 0));
00784         bool display = (alarmTime <= now);
00785 
00786         KAlarmEvent event(alarmTime, message, bg, type, flags);
00787         if (!audioFile.isEmpty())
00788                 event.setAudioFile(audioFile);
00789         switch (recurType)
00790         {
00791                 case KAlarmEvent::MINUTELY:
00792                         event.setRecurMinutely(repeatInterval, repeatCount, endTime);
00793                         break;
00794                 case KAlarmEvent::DAILY:
00795                         event.setRecurDaily(repeatInterval, repeatCount, endTime.date());
00796                         break;
00797                 case KAlarmEvent::WEEKLY:
00798                 {
00799                         QBitArray days(7);
00800                         days.setBit(QDate::currentDate().dayOfWeek() - 1);
00801                         event.setRecurWeekly(repeatInterval, days, repeatCount, endTime.date());
00802                         break;
00803                 }
00804                 case KAlarmEvent::MONTHLY_DAY:
00805                 {
00806                         QValueList<int> days;
00807                         days.append(QDate::currentDate().day());
00808                         event.setRecurMonthlyByDate(repeatInterval, days, repeatCount, endTime.date());
00809                         break;
00810                 }
00811                 case KAlarmEvent::ANNUAL_DATE:
00812                 {
00813                         QValueList<int> months;
00814                         months.append(QDate::currentDate().month());
00815                         event.setRecurAnnualByDate(repeatInterval, months, repeatCount, endTime.date());
00816                         break;
00817                 }
00818                 default:
00819                         recurType = KAlarmEvent::NO_RECUR;
00820                         break;
00821         }
00822         if (display)
00823         {
00824                 // Alarm is due for display already
00825                 execAlarm(event, event.firstAlarm(), false);
00826                 if (recurType == KAlarmEvent::NO_RECUR
00827                 ||  event.setNextOccurrence(now) == KAlarmEvent::NO_OCCURRENCE)
00828                         return true;
00829         }
00830         return addEvent(event, 0L);     // event instance will now belong to the calendar
00831 }
00832 
00833 /******************************************************************************
00834 * Called in response to a DCOP notification by the alarm daemon that an event
00835 * should be handled, i.e. displayed or cancelled.
00836 * Optionally display the event. Delete the event from the calendar file and
00837 * from every main window instance.
00838 */
00839 void KAlarmApp::handleEvent(const QString& urlString, const QString& eventID, EventFunc function)
00840 {
00841         kdDebug(5950) << "KAlarmApp::handleEvent(DCOP): " << eventID << endl;
00842         if (KURL(urlString).url() != mCalendar->urlString())
00843                 kdError(5950) << "KAlarmApp::handleEvent(DCOP): wrong calendar file " << urlString << endl;
00844         else
00845                 handleEvent(eventID, function);
00846 }
00847 
00848 /******************************************************************************
00849 * Either:
00850 * a) Display the event and then delete it if it has no outstanding repetitions.
00851 * b) Delete the event.
00852 * c) Reschedule the event for its next repetition. If none remain, delete it.
00853 * If the event is deleted, it is removed from the calendar file and from every
00854 * main window instance.
00855 */
00856 bool KAlarmApp::handleEvent(const QString& eventID, EventFunc function)
00857 {
00858         kdDebug(5950) << "KAlarmApp::handleEvent(): " << eventID << ", " << (function==EVENT_TRIGGER?"TRIGGER":function==EVENT_CANCEL?"CANCEL":function==EVENT_HANDLE?"HANDLE":"?") << endl;
00859         Event* kcalEvent = mCalendar->event(eventID);
00860         if (!kcalEvent)
00861         {
00862                 kdError(5950) << "KAlarmApp::handleEvent(): event ID not found: " << eventID << endl;
00863                 return false;
00864         }
00865         KAlarmEvent event(*kcalEvent);
00866         AlarmFunc alfunction = ALARM_TRIGGER;
00867         switch (function)
00868         {
00869                 case EVENT_TRIGGER:
00870                 {
00871                         // Only trigger one alarm from the event - we don't
00872                         // want multiple identical messages, for example.
00873                         KAlarmAlarm alarm = event.firstAlarm();
00874                         if (alarm.valid())
00875                                 handleAlarm(event, alarm, ALARM_TRIGGER, true);
00876                         break;
00877                 }
00878                 case EVENT_CANCEL:
00879                         deleteEvent(event, 0L, false);
00880                         break;
00881 
00882                 case EVENT_HANDLE:
00883                 {
00884                         QDateTime now = QDateTime::currentDateTime();
00885                         bool updateCalAndDisplay = false;
00886                         KAlarmAlarm displayAlarm;
00887                         // Check all the alarms in turn.
00888                         // Note that the main alarm is fetched before any other alarms.
00889                         for (KAlarmAlarm alarm = event.firstAlarm();  alarm.valid();  alarm = event.nextAlarm(alarm))
00890                         {
00891                                 // Check whether this alarm is due yet
00892                                 int secs = alarm.dateTime().secsTo(now);
00893                                 if (secs < 0)
00894                                 {
00895                                         kdDebug(5950) << "KAlarmApp::handleEvent(): alarm " << alarm.id() << ": not due\n";
00896                                         continue;
00897                                 }
00898                                 if (alarm.repeatAtLogin())
00899                                 {
00900                                         // Alarm is to be displayed at every login.
00901                                         // Check if the alarm has only just been set up.
00902                                         // (The alarm daemon will immediately notify that it is due
00903                                         //  since it is set up with a time in the past.)
00904                                         kdDebug(5950) << "KAlarmApp::handleEvent(): alarm " << alarm.id() << ": REPEAT_AT_LOGIN\n";
00905                                         if (secs < maxLateness())
00906                                                 continue;
00907 
00908                                         // Check if the main alarm is already being displayed.
00909                                         // (We don't want to display both at the same time.)
00910                                         if (displayAlarm.valid())
00911                                                 continue;
00912                                 }
00913                                 if (alarm.lateCancel())
00914                                 {
00915                                         // Alarm is due, and it is to be cancelled if late.
00916                                         kdDebug(5950) << "KAlarmApp::handleEvent(): alarm " << alarm.id() << ": LATE_CANCEL\n";
00917                                         bool late = false;
00918                                         bool cancel = false;
00919                                         if (event.anyTime())
00920                                         {
00921                                                 // The alarm has no time, so cancel it if its date is past
00922                                                 QDateTime limit(alarm.date().addDays(1), mSettings->startOfDay());
00923                                                 if (now >= limit)
00924                                                 {
00925                                                         // It's too late to display the scheduled occurrence.
00926                                                         // Find the last previous occurrence of the alarm.
00927                                                         QDateTime next;
00928                                                         KAlarmEvent::OccurType type = event.previousOccurrence(now, next);
00929                                                         switch (type)
00930                                                         {
00931                                                                 case KAlarmEvent::FIRST_OCCURRENCE:
00932                                                                 case KAlarmEvent::RECURRENCE_DATE:
00933                                                                 case KAlarmEvent::RECURRENCE_DATE_TIME:
00934                                                                 case KAlarmEvent::LAST_OCCURRENCE:
00935                                                                         limit.setDate(next.date().addDays(1));
00936                                                                         limit.setTime(mSettings->startOfDay());
00937                                                                         if (now >= limit)
00938                                                                         {
00939                                                                                 if (type == KAlarmEvent::LAST_OCCURRENCE)
00940                                                                                         cancel = true;
00941                                                                                 else
00942                                                                                         late = true;
00943                                                                         }
00944                                                                         break;
00945                                                                 case KAlarmEvent::NO_OCCURRENCE:
00946                                                                 default:
00947                                                                         late = true;
00948                                                                         break;
00949                                                         }
00950                                                 }
00951                                         }
00952                                         else
00953                                         {
00954                                                 // The alarm is timed. Allow it to be just over a minute late before cancelling it.
00955                                                 int maxlate = maxLateness();
00956                                                 if (secs > maxlate)
00957                                                 {
00958                                                         // It's over the maximum interval late.
00959                                                         // Find the last previous occurrence of the alarm.
00960                                                         QDateTime next;
00961                                                         KAlarmEvent::OccurType type = event.previousOccurrence(now, next);
00962                                                         switch (type)
00963                                                         {
00964                                                                 case KAlarmEvent::FIRST_OCCURRENCE:
00965                                                                 case KAlarmEvent::RECURRENCE_DATE:
00966                                                                 case KAlarmEvent::RECURRENCE_DATE_TIME:
00967                                                                 case KAlarmEvent::LAST_OCCURRENCE:
00968                                                                         if (next.secsTo(now) > maxlate)
00969                                                                         {
00970                                                                                 if (type == KAlarmEvent::LAST_OCCURRENCE)
00971                                                                                         cancel = true;
00972                                                                                 else
00973                                                                                         late = true;
00974                                                                         }
00975                                                                         break;
00976                                                                 case KAlarmEvent::NO_OCCURRENCE:
00977                                                                 default:
00978                                                                         late = true;
00979                                                                         break;
00980                                                         }
00981                                                 }
00982                                         }
00983 
00984                                         if (cancel)
00985                                         {
00986                                                 // All repetitions are finished, so cancel the event
00987                                                 handleAlarm(event, alarm, ALARM_CANCEL, false);
00988                                                 updateCalAndDisplay = true;
00989                                                 continue;
00990                                         }
00991                                         if (late)
00992                                         {
00993                                                 // The latest repetition was too long ago, so schedule the next one
00994                                                 handleAlarm(event, alarm, ALARM_RESCHEDULE, false);
00995                                                 updateCalAndDisplay = true;
00996                                                 continue;
00997                                         }
00998                                 }
00999                                 if (alfunction == ALARM_TRIGGER)
01000                                 {
01001                                         kdDebug(5950) << "KAlarmApp::handleEvent(): alarm " << alarm.id() << ": display\n";
01002                                         displayAlarm = alarm;             // note the alarm to be displayed
01003                                         alfunction = ALARM_RESCHEDULE;    // only trigger one alarm for the event
01004                                 }
01005                                 else
01006                                         kdDebug(5950) << "KAlarmApp::handleEvent(): alarm " << alarm.id() << ": skip\n";
01007                         }
01008 
01009                         // If there is an alarm to display, do this last after rescheduling/cancelling
01010                         // any others. This ensures that the updated event is only saved once to the calendar.
01011                         if (displayAlarm.valid())
01012                                 handleAlarm(event, displayAlarm, ALARM_TRIGGER, true);
01013                         else if (updateCalAndDisplay)
01014                                 updateEvent(event, 0L);     // update the window lists and calendar file
01015                         else
01016                                 kdDebug(5950) << "KAlarmApp::handleEvent(): no action\n";
01017                         break;
01018                 }
01019         }
01020         return true;
01021 }
01022 
01023 /******************************************************************************
01024 * Called when an alarm is displayed to reschedule it for its next repetition.
01025 * If no repetitions remain, cancel it.
01026 */
01027 void KAlarmApp::rescheduleAlarm(KAlarmEvent& event, int alarmID)
01028 {
01029         kdDebug(5950) << "KAlarmApp::rescheduleAlarm(): " << event.id() << ":" << alarmID << endl;
01030         Event* kcalEvent = mCalendar->event(event.id());
01031         if (!kcalEvent)
01032                 kdError(5950) << "KAlarmApp::rescheduleAlarm(): event ID not found: " << event.id() << endl;
01033         else
01034         {
01035                 KAlarmAlarm alarm = event.alarm(alarmID);
01036                 if (!alarm.valid())
01037                         kdError(5950) << "KAlarmApp::rescheduleAlarm(): alarm sequence not found: " << event.id() << ":" << alarmID << endl;
01038                 handleAlarm(event, alarm, ALARM_RESCHEDULE, true);
01039         }
01040 }
01041 
01042 /******************************************************************************
01043 * Either:
01044 * a) Display the alarm and then delete it if it has no outstanding repetitions.
01045 * b) Delete the alarm.
01046 * c) Reschedule the alarm for its next repetition. If none remain, delete it.
01047 * If the alarm is deleted and it is the last alarm for its event, the event is
01048 * removed from the calendar file and from every main window instance.
01049 */
01050 void KAlarmApp::handleAlarm(KAlarmEvent& event, KAlarmAlarm& alarm, AlarmFunc function, bool updateCalAndDisplay)
01051 {
01052         switch (function)
01053         {
01054                 case ALARM_TRIGGER:
01055                         kdDebug(5950) << "KAlarmApp::handleAlarm(): TRIGGER" << endl;
01056                         execAlarm(event, alarm, true);
01057                         break;
01058 
01059                 case ALARM_RESCHEDULE:
01060                 {
01061                         // Leave an alarm which repeats at every login until its main alarm is deleted
01062                         kdDebug(5950) << "KAlarmApp::handleAlarm(): RESCHEDULE" << endl;
01063                         bool update = false;
01064                         if (alarm.deferred())
01065                         {
01066                                 // It's an extra deferred alarm, so delete it
01067                                 event.removeAlarm(alarm.id());
01068                                 update = true;
01069                         }
01070                         else if (!alarm.repeatAtLogin())
01071                         {
01072                                 switch (event.setNextOccurrence(QDateTime::currentDateTime()))
01073                                 {
01074                                         case KAlarmEvent::NO_OCCURRENCE:
01075                                                 // All repetitions are finished, so cancel the event
01076                                                 if (alarm.id() == KAlarmEvent::MAIN_ALARM_ID  &&  !event.audioFile().isEmpty())
01077                                                         event.removeAlarm(KAlarmEvent::AUDIO_ALARM_ID);
01078                                                 handleAlarm(event, alarm, ALARM_CANCEL, updateCalAndDisplay);
01079                                                 break;
01080                                         case KAlarmEvent::RECURRENCE_DATE:
01081                                         case KAlarmEvent::RECURRENCE_DATE_TIME:
01082                                         case KAlarmEvent::LAST_OCCURRENCE:
01083                                                 // The event is due by now and repetitions still remain, so rewrite the event
01084                                                 if (updateCalAndDisplay)
01085                                                         update = true;
01086                                                 else
01087                                                         event.setUpdated();    // note that the calendar file needs to be updated
01088                                                 break;
01089                                         case KAlarmEvent::FIRST_OCCURRENCE:
01090                                                 // The first occurrence is still due?!?, so don't do anything
01091                                         default:
01092                                                 break;
01093                                 }
01094                                 if (event.deferred())
01095                                 {
01096                                         event.removeAlarm(KAlarmEvent::MAIN_ALARM_ID + KAlarmEvent::DEFERRAL_OFFSET);
01097                                         update = true;
01098                                 }
01099                         }
01100                         else if (updateCalAndDisplay  &&  event.updated())
01101                                 update = true;
01102                         if (update)
01103                                 updateEvent(event, 0);     // update the window lists and calendar file
01104                         break;
01105                 }
01106                 case ALARM_CANCEL:
01107                 {
01108                         kdDebug(5950) << "KAlarmApp::handleAlarm(): CANCEL" << endl;
01109                         event.removeAlarm(alarm.id());
01110                         if (!event.alarmCount())
01111                                 deleteEvent(event, 0L, false);
01112                         else if (updateCalAndDisplay)
01113                                 updateEvent(event, 0L);    // update the window lists and calendar file
01114                         break;
01115                 }
01116                 default:
01117                         kdError(5950) << "KAlarmApp::handleAlarm(): unknown function" << endl;
01118         }
01119 }
01120 
01121 /******************************************************************************
01122 * Execute an alarm by displaying its message or file, or executing its command.
01123 * Reply = false if an error message was output.
01124 */
01125 bool KAlarmApp::execAlarm(KAlarmEvent& event, const KAlarmAlarm& alarm, bool reschedule, bool allowDefer)
01126 {
01127         bool result = true;
01128         if (alarm.type() == KAlarmAlarm::COMMAND)
01129         {
01130                 QString command = event.cleanText();
01131                 kdDebug(5950) << "KAlarmApp::execAlarm(): COMMAND: " << command << endl;
01132                 KShellProcess proc;
01133                 proc << command;
01134                 if (!proc.start(KProcess::DontCare))
01135                 {
01136                         kdDebug(5950) << "KAlarmApp::execAlarm(): failed\n";
01137                         QString msg = i18n("Failed to execute command:");
01138                         (new MessageWin(QString("%1\n%2").arg(msg).arg(command), event, alarm, reschedule))->show();
01139                         result = false;
01140                 }
01141 #if 0
01142                 else (!proc.normalExit())
01143                 {
01144                         kdDebug(5950) << "KAlarmApp::execAlarm(): killed\n";
01145                         (new MessageWin(i18n("Command execution error:"), event, alarm, reschedule))->show();
01146                         result = false;
01147                 }
01148 #endif
01149                 if (reschedule)
01150                         rescheduleAlarm(event, alarm.id());
01151         }
01152 #ifdef KALARM_EMAIL
01153         else if (alarm.type() == KAlarmAlarm::EMAIL)
01154         {
01155                 QString addresses = event.emailAddresses();
01156                 kdDebug(5950) << "KAlarmApp::execAlarm(): EMAIL: " << command << endl;
01157                 if (1)
01158                 {
01159                         kdDebug(5950) << "KAlarmApp::execAlarm(): failed\n";
01160                         (new MessageWin(i18n("Failed to send email"), event, alarm, reschedule))->show();
01161                         result = false;
01162                 }
01163                 if (reschedule)
01164                         rescheduleAlarm(event, alarm.id());
01165         }
01166 #endif
01167         else
01168         {
01169                 // Display a message or file, provided that the same event isn't already being displayed
01170                 MessageWin* win = MessageWin::findEvent(event.id());
01171                 if (win  &&  (win->hasDefer() || alarm.repeatAtLogin()))
01172                         win->repeat();
01173                 else
01174                 {
01175                         // Either there isn't already a message for this event,
01176                         // or there is a repeat-at-login message with no Defer
01177                         // button, which needs to be replaced with a new message.
01178                         delete win;
01179                         (new MessageWin(event, alarm, reschedule, allowDefer))->show();
01180                 }
01181         }
01182         return result;
01183 }
01184 
01185 /******************************************************************************
01186 * Add a new alarm.
01187 * Save it in the calendar file and add it to every main window instance.
01188 * Parameters:
01189 *    win  = initiating main window instance (which has already been updated)
01190 */
01191 bool KAlarmApp::addEvent(const KAlarmEvent& event, KAlarmMainWindow* win)
01192 {
01193         kdDebug(5950) << "KAlarmApp::addEvent(): " << event.id() << endl;
01194         if (!initCheck())
01195                 return false;
01196 
01197         // Save the event details in the calendar file, and get the new event ID
01198         mCalendar->addEvent(event);
01199         mCalendar->save();
01200 
01201         // Tell the daemon to reread the calendar file
01202         reloadDaemon();
01203 
01204         // Update the window lists
01205         KAlarmMainWindow::addEvent(event, win);
01206         return true;
01207 }
01208 
01209 /******************************************************************************
01210 * Modify an alarm in every main window instance.
01211 * The new event will have a different event ID from the old one.
01212 * Parameters:
01213 *    win  = initiating main window instance (which has already been updated)
01214 */
01215 void KAlarmApp::modifyEvent(const QString& oldEventID, const KAlarmEvent& newEvent, KAlarmMainWindow* win)
01216 {
01217         kdDebug(5950) << "KAlarmApp::modifyEvent(): '" << oldEventID << endl;
01218 
01219         // Update the event in the calendar file, and get the new event ID
01220         mCalendar->deleteEvent(oldEventID);
01221         mCalendar->addEvent(newEvent);
01222         mCalendar->save();
01223 
01224         // Tell the daemon to reread the calendar file
01225         reloadDaemon();
01226 
01227         // Update the window lists
01228         KAlarmMainWindow::modifyEvent(oldEventID, newEvent, win);
01229 }
01230 
01231 /******************************************************************************
01232 * Update an alarm in every main window instance.
01233 * The new event will have the same event ID as the old one.
01234 * Parameters:
01235 *    win  = initiating main window instance (which has already been updated)
01236 */
01237 void KAlarmApp::updateEvent(const KAlarmEvent& event, KAlarmMainWindow* win)
01238 {
01239         kdDebug(5950) << "KAlarmApp::updateEvent(): " << event.id() << endl;
01240 
01241         // Update the event in the calendar file
01242         const_cast<KAlarmEvent&>(event).incrementRevision();
01243         mCalendar->updateEvent(event);
01244         mCalendar->save();
01245 
01246         // Tell the daemon to reread the calendar file
01247         reloadDaemon();
01248 
01249         // Update the window lists
01250         KAlarmMainWindow::modifyEvent(event, win);
01251 }
01252 
01253 /******************************************************************************
01254 * Delete an alarm from every main window instance.
01255 * Parameters:
01256 *    win  = initiating main window instance (which has already been updated)
01257 */
01258 void KAlarmApp::deleteEvent(KAlarmEvent& event, KAlarmMainWindow* win, bool tellDaemon)
01259 {
01260         kdDebug(5950) << "KAlarmApp::deleteEvent(): " << event.id() << endl;
01261 
01262         // Update the window lists
01263         KAlarmMainWindow::deleteEvent(event, win);
01264 
01265         // Delete the event from the calendar file
01266         mCalendar->deleteEvent(event.id());
01267         mCalendar->save();
01268 
01269         // Tell the daemon to reread the calendar file
01270         if (tellDaemon)
01271                 reloadDaemon();
01272 }
01273 
01274 /******************************************************************************
01275 * Set up the DCOP handlers.
01276 */
01277 void KAlarmApp::setUpDcop()
01278 {
01279         if (!mDcopHandler)
01280         {
01281                 mDcopHandler      = new DcopHandler(QString::fromLatin1(DCOP_OBJECT_NAME));
01282                 mDaemonGuiHandler = new DaemonGuiHandler(QString::fromLatin1(GUI_DCOP_OBJECT_NAME));
01283         }
01284 }
01285 
01286 /******************************************************************************
01287 * If this is the first time through, open the calendar file, optionally start
01288 * the alarm daemon and register with it, and set up the DCOP handler.
01289 */
01290 bool KAlarmApp::initCheck(bool calendarOnly)
01291 {
01292         if (!mCalendar->isOpen())
01293         {
01294                 kdDebug(5950) << "KAlarmApp::initCheck(): opening calendar\n";
01295 
01296                 // First time through. Open the calendar file.
01297                 if (!mCalendar->open())
01298                         return false;
01299 
01300                 if (!mStartOfDay.isValid())
01301                         changeStartOfDay();   // start of day time has changed, so adjust date-only alarms
01302 
01303                 if (!calendarOnly)
01304                         startDaemon();        // make sure the alarm daemon is running
01305         }
01306         else if (!mDaemonRegistered)
01307                 startDaemon();
01308 
01309         if (!calendarOnly)
01310                 setUpDcop();            // we're now ready to handle DCOP calls, so set up handlers
01311         return true;
01312 }
01313 
01314 /******************************************************************************
01315 * Start the alarm daemon if necessary, and register this application with it.
01316 */
01317 void KAlarmApp::startDaemon()
01318 {
01319         kdDebug(5950) << "KAlarmApp::startDaemon()\n";
01320         mCalendar->getURL();    // check that the calendar file name is OK - program exit if not
01321         if (!dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
01322         {
01323                 // Start the alarm daemon. It is a KUniqueApplication, which means that
01324                 // there is automatically only one instance of the alarm daemon running.
01325                 QString execStr = locate("exe",QString::fromLatin1(DAEMON_APP_NAME));
01326                 system(QFile::encodeName(execStr));
01327                 kdDebug(5950) << "KAlarmApp::startDaemon(): Alarm daemon started" << endl;
01328         }
01329 
01330         // Register this application with the alarm daemon
01331         registerWithDaemon(false);
01332 
01333         // Tell alarm daemon to load the calendar
01334         {
01335                 QByteArray data;
01336                 QDataStream arg(data, IO_WriteOnly);
01337                 arg << QCString(aboutData()->appName()) << mCalendar->urlString();
01338                 if (!dcopClient()->send(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT, "addMsgCal(QCString,QString)", data))
01339                         kdDebug(5950) << "KAlarmApp::startDaemon(): addCal dcop send failed" << endl;
01340         }
01341 
01342         mDaemonRegistered = true;
01343         kdDebug(5950) << "KAlarmApp::startDaemon(): started daemon" << endl;
01344 }
01345 
01346 /******************************************************************************
01347 * Start the alarm daemon if necessary, and register this application with it.
01348 */
01349 void KAlarmApp::registerWithDaemon(bool reregister)
01350 {
01351         kdDebug(5950) << (reregister ? "KAlarmApp::reregisterWithDaemon()" : "KAlarmApp::registerWithDaemon()") << endl;
01352         QByteArray data;
01353         QDataStream arg(data, IO_WriteOnly);
01354         arg << QCString(aboutData()->appName()) << aboutData()->programName()
01355             << QCString(DCOP_OBJECT_NAME)
01356             << (int)(mDisableAlarmsIfStopped ? ClientInfo::NO_START_NOTIFY : ClientInfo::COMMAND_LINE_NOTIFY)
01357             << (Q_INT8)0;
01358         const char* func = reregister ? "reregisterApp(QCString,QString,QCString,int,bool)" : "registerApp(QCString,QString,QCString,int,bool)";
01359         if (!dcopClient()->send(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT, func, data))
01360                 kdDebug(5950) << "KAlarmApp::registerWithDaemon(): registerApp dcop send failed" << endl;
01361 }
01362 
01363 /******************************************************************************
01364 * Stop the alarm daemon if it is running.
01365 */
01366 bool KAlarmApp::stopDaemon()
01367 {
01368         kdDebug(5950) << "KAlarmApp::stopDaemon()" << endl;
01369         if (dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
01370         {
01371                 QByteArray data;
01372                 if (!dcopClient()->send(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT, "quit()", data))
01373                 {
01374                         kdError(5950) << "KAlarmApp::stopDaemon(): quit dcop send failed" << endl;
01375                         return false;
01376                 }
01377         }
01378         return true;
01379 }
01380 
01381 /******************************************************************************
01382 * Reset the alarm daemon and reload the calendar.
01383 * If the daemon is not already running, start it.
01384 */
01385 void KAlarmApp::resetDaemon()
01386 {
01387         kdDebug(5950) << "KAlarmApp::resetDaemon()" << endl;
01388         mCalendar->reload();
01389         KAlarmMainWindow::refresh();
01390         if (!dcopClient()->isApplicationRegistered(DAEMON_APP_NAME))
01391                 startDaemon();
01392         else
01393         {
01394                 QByteArray data;
01395                 QDataStream arg(data, IO_WriteOnly);
01396                 arg << QCString(aboutData()->appName()) << mCalendar->urlString();
01397                 if (!dcopClient()->send(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT, "resetMsgCal(QCString,QString)", data))
01398                         kdDebug(5950) << "KAlarmApp::resetDaemon(): addCal dcop send failed" << endl;
01399         }
01400 }
01401 
01402 /******************************************************************************
01403 * Tell the alarm daemon to reread the calendar file.
01404 */
01405 void KAlarmApp::reloadDaemon()
01406 {
01407         QByteArray data;
01408         QDataStream arg(data, IO_WriteOnly);
01409         arg << QCString(aboutData()->appName()) << mCalendar->urlString();
01410         if (!dcopClient()->send(DAEMON_APP_NAME, DAEMON_DCOP_OBJECT, "reloadMsgCal(QCString,QString)", data))
01411                 kdDebug(5950) << "KAlarmApp::reloadDaemon(): dcop send failed" << endl;
01412 }
01413 
01414 /******************************************************************************
01415 * Check whether the alarm daemon is currently running.
01416 */
01417 bool KAlarmApp::isDaemonRunning()
01418 {
01419         bool running = dcopClient()->isApplicationRegistered(DAEMON_APP_NAME);
01420         if (running != mDaemonRunning)
01421         {
01422                 // Daemon's status has changed
01423                 mDaemonRunning = running;
01424                 if (mDaemonRunning)
01425                         startDaemon();      // re-register with the daemon
01426         }
01427         return mDaemonRunning;
01428 }
01429 
01430 /******************************************************************************
01431 * Read the alarm daemon's alarm check interval from its config file. If it has
01432 * reduced, any late-cancel alarms which are already due could potentially be
01433 * cancelled erroneously. To avoid this, note the effective last time that it
01434 * will have checked alarms.
01435 */
01436 void KAlarmApp::readDaemonCheckInterval()
01437 {
01438         KConfig config(locate("config", DAEMON_APP_NAME_DEF"rc"));
01439         config.setGroup("General");
01440         int checkInterval = 60 * config.readNumEntry("CheckInterval", 1);
01441         if (checkInterval < mDaemonCheckInterval)
01442         {
01443                 // The daemon check interval has reduced,
01444                 // Note the effective last time that the daemon checked alarms.
01445                 QDateTime now = QDateTime::currentDateTime();
01446                 mLastDaemonCheck = now.addSecs(-mDaemonCheckInterval);
01447                 mNextDaemonCheck = now.addSecs(checkInterval);
01448         }
01449         mDaemonCheckInterval = checkInterval;
01450 }
01451 
01452 /******************************************************************************
01453 * Find the maximum number of seconds late which a late-cancel alarm is allowed
01454 * to be. This is calculated as the alarm daemon's check interval, plus a few
01455 * seconds leeway to cater for any timing irregularities.
01456 */
01457 int KAlarmApp::maxLateness()
01458 {
01459         static const int LATENESS_LEEWAY = 5;
01460 
01461         readDaemonCheckInterval();
01462         if (mLastDaemonCheck.isValid())
01463         {
01464                 QDateTime now = QDateTime::currentDateTime();
01465                 if (mNextDaemonCheck > now)
01466                 {
01467                         // Daemon's check interval has just reduced, so allow extra time
01468                         return mLastDaemonCheck.secsTo(now) + LATENESS_LEEWAY;
01469                 }
01470                 mLastDaemonCheck = QDateTime();
01471         }
01472         return mDaemonCheckInterval + LATENESS_LEEWAY;
01473 }
01474 
01475 /******************************************************************************
01476 *  Read the size for the specified window from the config file, for the
01477 *  current screen resolution.
01478 *  Reply = window size.
01479 */
01480 QSize KAlarmApp::readConfigWindowSize(const char* window, const QSize& defaultSize)
01481 {
01482         KConfig* config = KGlobal::config();
01483         config->setGroup(QString::fromLatin1(window));
01484         QWidget* desktop = KApplication::desktop();
01485         return QSize(config->readNumEntry(QString::fromLatin1("Width %1").arg(desktop->width()), defaultSize.width()),
01486                      config->readNumEntry(QString::fromLatin1("Height %1").arg(desktop->height()), defaultSize.height()));
01487 }
01488 
01489 /******************************************************************************
01490 *  Write the size for the specified window to the config file, for the
01491 *  current screen resolution.
01492 */
01493 void KAlarmApp::writeConfigWindowSize(const char* window, const QSize& size)
01494 {
01495         KConfig* config = KGlobal::config();
01496         config->setGroup(QString::fromLatin1(window));
01497         QWidget* desktop = KApplication::desktop();
01498         config->writeEntry(QString::fromLatin1("Width %1").arg(desktop->width()), size.width());
01499         config->writeEntry(QString::fromLatin1("Height %1").arg(desktop->height()), size.height());
01500         config->sync();
01501 }
01502 
01503 /******************************************************************************
01504 * Check whether a file appears to be a text file by looking at its mime type.
01505 * Reply = 0 if not a text file
01506 *       = 1 if a plain text file
01507 *       = 2 if a formatted text file.
01508 */
01509 int KAlarmApp::isTextFile(const KURL& url)
01510 {
01511         static const char* applicationTypes[] = {
01512                 "x-shellscript", "x-nawk", "x-awk", "x-perl", "x-python",
01513                 "x-desktop", "x-troff", 0 };
01514         static const char* formattedTextTypes[] = {
01515                 "html", "xml", 0 };
01516 
01517         QString mimetype = KFileItem(-1, -1, url).mimetype();
01518         int slash = mimetype.find('/');
01519         if (slash < 0)
01520                 return 0;
01521         QString subtype = mimetype.mid(slash + 1);
01522         if (mimetype.startsWith(QString::fromLatin1("application")))
01523         {
01524                 for (int i = 0;  applicationTypes[i];  ++i)
01525                         if (!strcmp(subtype, applicationTypes[i]))
01526                                 return 1;
01527         }
01528         else if (mimetype.startsWith(QString::fromLatin1("text")))
01529         {
01530                 for (int i = 0;  formattedTextTypes[i];  ++i)
01531                         if (!strcmp(subtype, formattedTextTypes[i]))
01532                                 return 2;
01533                 return 1;
01534         }
01535         return 0;
01536 }
01537 
01538 /******************************************************************************
01539 * This class's function is simply to act as a receiver for DCOP requests.
01540 */
01541 DcopHandler::DcopHandler(const char* dcopObject)
01542         : QWidget(),
01543           DCOPObject(dcopObject)
01544 {
01545         kdDebug(5950) << "DcopHandler::DcopHandler()\n";
01546 }
01547 
01548 /******************************************************************************
01549 * Process a DCOP request.
01550 */
01551 bool DcopHandler::process(const QCString& func, const QByteArray& data, QCString& replyType, QByteArray&)
01552 {
01553         kdDebug(5950) << "DcopHandler::process(): " << func << endl;
01554         enum
01555         {
01556                 ERR            = 0,
01557                 OPERATION      = 0x0007,    // mask for main operation
01558                   HANDLE       = 0x0001,
01559                   CANCEL       = 0x0002,
01560                   TRIGGER      = 0x0003,
01561                   SCHEDULE     = 0x0004,
01562                 ALARM_TYPE     = 0x00F0,    // mask for SCHEDULE alarm type
01563                   MESSAGE      = 0x0010,
01564                   FILE         = 0x0020,
01565                   COMMAND      = 0x0030,
01566                 SCH_FLAGS      = 0x0F00,    // mask for SCHEDULE flags
01567                   REP_COUNT    = 0x0100,
01568                   REP_END      = 0x0200,
01569                 OLD            = 0x1000     // old-style deprecated method
01570         };
01571         int function;
01572         if      (func == "handleEvent(const QString&,const QString&)"
01573         ||       func == "handleEvent(QString,QString)")
01574                 function = HANDLE;
01575         else if (func == "cancelEvent(const QString&,const QString&)"
01576         ||       func == "cancelEvent(QString,QString)"
01577         ||       func == "cancelMessage(const QString&,const QString&)"    // deprecated: backwards compatibility with KAlarm pre-0.6
01578         ||       func == "cancelMessage(QString,QString)")                 // deprecated: backwards compatibility with KAlarm pre-0.6
01579                 function = CANCEL;
01580         else if (func == "triggerEvent(const QString&,const QString&)"
01581         ||       func == "triggerEvent(QString,QString)"
01582         ||       func == "displayMessage(const QString&,const QString&)"   // deprecated: backwards compatibility with KAlarm pre-0.6
01583         ||       func == "displayMessage(QString,QString)")                // deprecated: backwards compatibility with KAlarm pre-0.6
01584                 function = TRIGGER;
01585 
01586         else if (func == "scheduleMessage(const QString&,const QDateTime&,QColor,Q_UINT32,const QString&)"
01587         ||       func == "scheduleMessage(QString,QDateTime,QColor,Q_UINT32,QString)")
01588                 function = SCHEDULE | MESSAGE;
01589         else if (func == "scheduleFile(const QString&,const QDateTime&,QColor,Q_UINT32,const QString&)"
01590         ||       func == "scheduleFile(QString,QDateTime,QColor,Q_UINT32,QString)")
01591                 function = SCHEDULE | FILE;
01592         else if (func == "scheduleCommand(const QString&,const QDateTime&,Q_UINT32)"
01593         ||       func == "scheduleCommand(QString,QDateTime,Q_UINT32)")
01594                 function = SCHEDULE | COMMAND;
01595 
01596         else if (func == "scheduleMessage(const QString&,const QDateTime&,QColor,Q_UINT32,const QString&,Q_INT32,Q_INT32,Q_INT32)"
01597         ||       func == "scheduleMessage(QString,QDateTime,QColor,Q_UINT32,QString,Q_INT32,Q_INT32,Q_INT32)")
01598                 function = SCHEDULE | MESSAGE | REP_COUNT;
01599         else if (func == "scheduleFile(const QString&,const QDateTime&,QColor,Q_UINT32,const QString&,Q_INT32,Q_INT32,Q_INT32)"
01600         ||       func == "scheduleFile(QString,QDateTime,QColor,Q_UINT32,QString,Q_INT32,Q_INT32,Q_INT32)")
01601                 function = SCHEDULE | FILE | REP_COUNT;
01602         else if (func == "scheduleCommand(const QString&,const QDateTime&,Q_UINT32,Q_INT32,Q_INT32,Q_INT32)"
01603         ||       func == "scheduleCommand(QString,QDateTime,Q_UINT32,Q_INT32,Q_INT32,Q_INT32)")
01604                 function = SCHEDULE | COMMAND | REP_COUNT;
01605 
01606         else if (func == "scheduleMessage(const QString&,const QDateTime&,QColor,Q_UINT32,const QString&,Q_INT32,Q_INT32,const QDateTime&)"
01607         ||       func == "scheduleMessage(QString,QDateTime,QColor,Q_UINT32,QString,Q_INT32,Q_INT32,QDateTime)")
01608                 function = SCHEDULE | MESSAGE | REP_END;
01609         else if (func == "scheduleFile(const QString&,const QDateTime&,QColor,Q_UINT32,const QString&,Q_INT32,Q_INT32,const QDateTime&)"
01610         ||       func == "scheduleFile(QString,QDateTime,QColor,Q_UINT32,QString,Q_INT32,Q_INT32,QDateTime)")
01611                 function = SCHEDULE | FILE | REP_END;
01612         else if (func == "scheduleCommand(const QString&,const QDateTime&,Q_UINT32,Q_INT32,Q_INT32,const QDateTime&)"
01613         ||       func == "scheduleCommand(QString,QDateTime,Q_UINT32,Q_INT32,Q_INT32,QDateTime)")
01614                 function = SCHEDULE | COMMAND | REP_END;
01615 
01616         // Deprecated methods: backwards compatibility with KAlarm pre-0.7
01617         else if (func == "scheduleMessage(const QString&,const QDateTime&,QColor,Q_UINT32,Q_INT32,Q_INT32)"
01618         ||       func == "scheduleMessage(QString,QDateTime,QColor,Q_UINT32,Q_INT32,Q_INT32)")
01619                 function = SCHEDULE | MESSAGE | REP_COUNT | OLD;
01620         else if (func == "scheduleFile(const QString&,const QDateTime&,QColor,Q_UINT32,Q_INT32,Q_INT32)"
01621         ||       func == "scheduleFile(QString,QDateTime,QColor,Q_UINT32,Q_INT32,Q_INT32)")
01622                 function = SCHEDULE | FILE | REP_COUNT | OLD;
01623         else if (func == "scheduleCommand(const QString&,const QDateTime&,Q_UINT32,Q_INT32,Q_INT32)"
01624         ||       func == "scheduleCommand(QString,QDateTime,Q_UINT32,Q_INT32,Q_INT32)")
01625                 function = SCHEDULE | COMMAND | REP_COUNT | OLD;
01626         else
01627         {
01628                 kdDebug(5950) << "DcopHandler::process(): unknown DCOP function" << endl;
01629                 return false;
01630         }
01631 
01632         switch (function & OPERATION)
01633         {
01634                 case HANDLE:        // trigger or cancel event with specified ID from calendar file
01635                 case CANCEL:        // cancel event with specified ID from calendar file
01636                 case TRIGGER:       // trigger event with specified ID in calendar file
01637                 {
01638 
01639                         QDataStream arg(data, IO_ReadOnly);
01640                         QString urlString, vuid;
01641                         arg >> urlString >> vuid;
01642                         replyType = "void";
01643                         switch (function)
01644                         {
01645                                 case HANDLE:
01646                                         theApp()->handleEvent(urlString, vuid);
01647                                         break;
01648                                 case CANCEL:
01649                                         theApp()->deleteEvent(urlString, vuid);
01650                                         break;
01651                                 case TRIGGER:
01652                                         theApp()->triggerEvent(urlString, vuid);
01653                                         break;
01654                         }
01655                         break;
01656                 }
01657                 case SCHEDULE:      // schedule a new event
01658                 {
01659                         KAlarmAlarm::Type type;
01660                         switch (function & ALARM_TYPE)
01661                         {
01662                                 case MESSAGE:  type = KAlarmAlarm::MESSAGE;  break;
01663                                 case FILE:     type = KAlarmAlarm::FILE;     break;
01664                                 case COMMAND:  type = KAlarmAlarm::COMMAND;  break;
01665                                 default:  return false;
01666                         }
01667                         QDataStream arg(data, IO_ReadOnly);
01668                         QString   text, audioFile;
01669                         QDateTime dateTime, endTime;
01670                         QColor    bgColour;
01671                         Q_UINT32  flags;
01672                         KAlarmEvent::RecurType recurType = KAlarmEvent::NO_RECUR;
01673                         Q_INT32   repeatCount = 0;
01674                         Q_INT32   repeatInterval = 0;
01675                         arg >> text;
01676                         arg.readRawBytes((char*)&dateTime, sizeof(dateTime));
01677                         if (type != KAlarmAlarm::COMMAND)
01678                                 arg.readRawBytes((char*)&bgColour, sizeof(bgColour));
01679                         arg >> flags;
01680                         if (!(function & OLD))
01681                                 arg >> audioFile;
01682                         if (function & (REP_COUNT | REP_END))
01683                         {
01684                                 if (function & OLD)
01685                                 {
01686                                         // Backwards compatibility with KAlarm pre-0.7
01687                                         recurType = KAlarmEvent::MINUTELY;
01688                                         arg >> repeatCount >> repeatInterval;
01689                                         ++repeatCount;
01690                                 }
01691                                 else
01692                                 {
01693                                         Q_INT32 type;
01694                                         arg >> type >> repeatInterval;
01695                                         recurType = KAlarmEvent::RecurType(type);
01696                                         switch (recurType)
01697                                         {
01698                                                 case KAlarmEvent::MINUTELY:
01699                                                 case KAlarmEvent::DAILY:
01700                                                 case KAlarmEvent::WEEKLY:
01701                                                 case KAlarmEvent::MONTHLY_DAY:
01702                                                 case KAlarmEvent::ANNUAL_DATE:
01703                                                         break;
01704                                                 default:
01705                                                         kdDebug(5950) << "DcopHandler::process(): invalid simple repetition type: " << type << endl;
01706                                                         return false;
01707                                         }
01708                                         if (function & REP_COUNT)
01709                                                 arg >> repeatCount;
01710                                         else
01711                                                 arg.readRawBytes((char*)&endTime, sizeof(endTime));
01712 
01713                                 }
01714                         }
01715                         theApp()->scheduleEvent(text, dateTime, bgColour, flags, audioFile, type, recurType, repeatInterval, repeatCount, endTime);
01716                         break;
01717                 }
01718         }
01719         replyType = "void";
01720         return true;
01721 }
01722 
01723 /******************************************************************************
01724 *  Convert the --time parameter string into a date/time or date value.
01725 *  The parameter is in the form [[[yyyy-]mm-]dd-]hh:mm or yyyy-mm-dd.
01726 *  Reply = true if successful.
01727 */
01728 static bool convWakeTime(const QCString timeParam, QDateTime& dateTime, bool& noTime)
01729 {
01730         if (timeParam.length() > 19)
01731                 return false;
01732         char timeStr[20];
01733         strcpy(timeStr, timeParam);
01734         int dt[5] = { -1, -1, -1, -1, -1 };
01735         char* s;
01736         char* end;
01737         // Get the minute value
01738         if ((s = strchr(timeStr, ':')) == 0L)
01739                 noTime = true;
01740         else
01741         {
01742                 noTime = false;
01743                 *s++ = 0;
01744                 dt[4] = strtoul(s, &end, 10);
01745                 if (end == s  ||  *end  ||  dt[4] >= 60)
01746                         return false;
01747                 // Get the hour value
01748                 if ((s = strrchr(timeStr, '-')) == 0L)
01749                         s = timeStr;
01750                 else
01751                         *s++ = 0;
01752                 dt[3] = strtoul(s, &end, 10);
01753                 if (end == s  ||  *end  ||  dt[3] >= 24)
01754                         return false;
01755         }
01756         bool dateSet = false;
01757         if (s != timeStr)
01758         {
01759                 dateSet = true;
01760                 // Get the day value
01761                 if ((s = strrchr(timeStr, '-')) == 0L)
01762                         s = timeStr;
01763                 else
01764                         *s++ = 0;
01765                 dt[2] = strtoul(s, &end, 10);
01766                 if (end == s  ||  *end  ||  dt[2] == 0  ||  dt[2] > 31)
01767                         return false;
01768                 if (s != timeStr)
01769                 {
01770                         // Get the month value
01771                         if ((s = strrchr(timeStr, '-')) == 0L)
01772                                 s = timeStr;
01773                         else
01774                                 *s++ = 0;
01775                         dt[1] = strtoul(s, &end, 10);
01776                         if (end == s  ||  *end  ||  dt[1] == 0  ||  dt[1] > 12)
01777                                 return false;
01778                         if (s != timeStr)
01779                         {
01780                                 // Get the year value
01781                                 dt[0] = strtoul(timeStr, &end, 10);
01782                                 if (end == timeStr  ||  *end)
01783                                         return false;
01784                         }
01785                 }
01786         }
01787 
01788         QDate date(dt[0], dt[1], dt[2]);
01789         QTime time(0, 0, 0);
01790         if (noTime)
01791         {
01792                 // No time was specified, so the full date must have been specified
01793                 if (dt[0] < 0)
01794                         return false;
01795         }
01796         else
01797         {
01798                 // Compile the values into a date/time structure
01799                 QDateTime now = QDateTime::currentDateTime();
01800                 if (dt[0] < 0)
01801                         date.setYMD(now.date().year(),
01802                                     (dt[1] < 0 ? now.date().month() : dt[1]),
01803                                     (dt[2] < 0 ? now.date().day() : dt[2]));
01804                 time.setHMS(dt[3], dt[4], 0);
01805                 if (!dateSet  &&  time < now.time())
01806                         date = date.addDays(1);
01807         }
01808         if (!date.isValid())
01809                 return false;
01810         dateTime.setDate(date);
01811         dateTime.setTime(time);
01812         return true;
01813 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sat Oct 18 02:47:26 2003 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001