00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kalarm.h"
00022 #include "kalarmapp.moc"
00023
00024 #include "alarmcalendar.h"
00025 #include "eventlistmodel.h"
00026 #include "alarmlistview.h"
00027 #include "birthdaymodel.h"
00028 #include "editdlg.h"
00029 #include "dbushandler.h"
00030 #include "functions.h"
00031 #include "kamail.h"
00032 #include "karecurrence.h"
00033 #include "mainwindow.h"
00034 #include "messagebox.h"
00035 #include "messagewin.h"
00036 #include "preferences.h"
00037 #include "prefdlg.h"
00038 #include "shellprocess.h"
00039 #include "startdaytimer.h"
00040 #include "traywindow.h"
00041
00042 #include <stdlib.h>
00043 #include <ctype.h>
00044 #include <iostream>
00045 #include <climits>
00046
00047 #include <QObject>
00048 #include <QTimer>
00049 #include <QRegExp>
00050 #include <QFile>
00051 #include <QByteArray>
00052 #include <QTextStream>
00053
00054 #include <kcmdlineargs.h>
00055 #include <klocale.h>
00056 #include <kstandarddirs.h>
00057 #include <kconfig.h>
00058 #include <kaboutdata.h>
00059 #include <ktemporaryfile.h>
00060 #include <kfileitem.h>
00061 #include <kglobal.h>
00062 #include <kstandardguiitem.h>
00063 #include <kservicetypetrader.h>
00064 #include <netwm.h>
00065 #include <kdebug.h>
00066 #include <kshell.h>
00067
00068 static bool convInterval(const QByteArray& timeParam, KARecurrence::Type&, int& timeInterval, bool allowMonthYear = false);
00069
00070
00071
00072
00073
00074
00075 static inline int maxLateness(int lateCancel)
00076 {
00077 static const int LATENESS_LEEWAY = 5;
00078 int lc = (lateCancel >= 1) ? (lateCancel - 1)*60 : 0;
00079 return LATENESS_LEEWAY + lc;
00080 }
00081
00082
00083 KAlarmApp* KAlarmApp::theInstance = 0;
00084 int KAlarmApp::mActiveCount = 0;
00085 int KAlarmApp::mFatalError = 0;
00086 QString KAlarmApp::mFatalMessage;
00087
00088
00089
00090
00091
00092 KAlarmApp::KAlarmApp()
00093 : KUniqueApplication(),
00094 mInitialised(false),
00095 mQuitting(false),
00096 mLoginAlarmsDone(false),
00097 mDBusHandler(new DBusHandler()),
00098 mTrayWindow(0),
00099 mAlarmTimer(new QTimer(this)),
00100 mArchivedPurgeDays(-1),
00101 mPurgeDaysQueued(-1),
00102 mPendingQuit(false),
00103 mProcessingQueue(false),
00104 mSessionClosingDown(false),
00105 mAlarmsEnabled(true),
00106 mSpeechEnabled(false)
00107 {
00108 kDebug();
00109 mAlarmTimer->setSingleShot(true);
00110 connect(mAlarmTimer, SIGNAL(timeout()), SLOT(checkNextDueAlarm()));
00111
00112 setQuitOnLastWindowClosed(false);
00113 Preferences::self()->readConfig();
00114 Preferences::setAutoStart(true);
00115 Preferences::self()->writeConfig();
00116 Preferences::connect(SIGNAL(startOfDayChanged(const QTime&, const QTime&)), this, SLOT(changeStartOfDay()));
00117 Preferences::connect(SIGNAL(feb29TypeChanged(Feb29Type)), this, SLOT(slotFeb29TypeChanged(Feb29Type)));
00118 Preferences::connect(SIGNAL(showInSystemTrayChanged(bool)), this, SLOT(slotShowInSystemTrayChanged()));
00119 Preferences::connect(SIGNAL(archivedKeepDaysChanged(int)), this, SLOT(setArchivePurgeDays()));
00120 KARecurrence::setDefaultFeb29Type(Preferences::defaultFeb29Type());
00121
00122 if (AlarmCalendar::initialiseCalendars())
00123 {
00124 connect(AlarmCalendar::resources(), SIGNAL(earliestAlarmChanged()), SLOT(checkNextDueAlarm()));
00125
00126 KConfigGroup config(KGlobal::config(), "General");
00127 mNoSystemTray = config.readEntry("NoSystemTray", false);
00128 mOldShowInSystemTray = wantShowInSystemTray();
00129 mStartOfDay = Preferences::startOfDay();
00130 if (Preferences::hasStartOfDayChanged())
00131 mStartOfDay.setHMS(100,0,0);
00132 DateTime::setStartOfDay(mStartOfDay);
00133 mPrefsArchivedColour = Preferences::archivedColour();
00134 }
00135
00136
00137 mSpeechEnabled = (KServiceTypeTrader::self()->query("DBUS/Text-to-Speech", "Name == 'KTTSD'").count() > 0);
00138 if (!mSpeechEnabled)
00139 kDebug() << "Speech synthesis disabled (KTTSD not found)";
00140
00141 QString korg = QLatin1String("korganizer");
00142 mKOrganizerEnabled = !KStandardDirs::locate("exe", korg).isNull() || !KStandardDirs::findExe(korg).isNull();
00143 if (!mKOrganizerEnabled)
00144 kDebug() << "KOrganizer options disabled (KOrganizer not found)";
00145 }
00146
00147
00148
00149 KAlarmApp::~KAlarmApp()
00150 {
00151 while (!mCommandProcesses.isEmpty())
00152 {
00153 ProcData* pd = mCommandProcesses[0];
00154 mCommandProcesses.pop_front();
00155 delete pd;
00156 }
00157 AlarmCalendar::terminateCalendars();
00158 }
00159
00160
00161
00162
00163
00164 KAlarmApp* KAlarmApp::getInstance()
00165 {
00166 if (!theInstance)
00167 {
00168 theInstance = new KAlarmApp;
00169
00170 if (mFatalError)
00171 theInstance->quitFatal();
00172 }
00173 return theInstance;
00174 }
00175
00176
00177
00178
00179 bool KAlarmApp::restoreSession()
00180 {
00181 if (!isSessionRestored())
00182 return false;
00183 if (mFatalError)
00184 {
00185 quitFatal();
00186 return false;
00187 }
00188
00189
00190 kDebug() << "Restoring";
00191 ++mActiveCount;
00192 if (!initCheck(true))
00193 {
00194 --mActiveCount;
00195 quitIf(1, true);
00196 return true;
00197 }
00198 MainWindow* trayParent = 0;
00199 for (int i = 1; KMainWindow::canBeRestored(i); ++i)
00200 {
00201 QString type = KMainWindow::classNameOfToplevel(i);
00202 if (type == QLatin1String("MainWindow"))
00203 {
00204 MainWindow* win = MainWindow::create(true);
00205 win->restore(i, false);
00206 if (win->isHiddenTrayParent())
00207 trayParent = win;
00208 else
00209 win->show();
00210 }
00211 else if (type == QLatin1String("MessageWin"))
00212 {
00213 MessageWin* win = new MessageWin;
00214 win->restore(i, false);
00215 if (win->isValid())
00216 win->show();
00217 else
00218 delete win;
00219 }
00220 }
00221 startProcessQueue();
00222
00223
00224 if (MainWindow::count() && wantShowInSystemTray())
00225 {
00226 displayTrayIcon(true, trayParent);
00227
00228
00229 if (trayParent)
00230 trayParent->hide();
00231 }
00232
00233 --mActiveCount;
00234 quitIf(0);
00235 return true;
00236 }
00237
00238
00239
00240
00241
00242 int KAlarmApp::newInstance()
00243 {
00244 kDebug();
00245 if (mFatalError)
00246 {
00247 quitFatal();
00248 return 1;
00249 }
00250 ++mActiveCount;
00251 int exitCode = 0;
00252 static bool firstInstance = true;
00253 bool dontRedisplay = false;
00254 if (!firstInstance || !isSessionRestored())
00255 {
00256 QString usage;
00257 KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
00258
00259
00260
00261 do
00262 {
00263 #define USAGE(message) { usage = message; break; }
00264 if (args->isSet("tray"))
00265 {
00266
00267 kDebug() << "--tray";
00268 args->clear();
00269 if (!KSystemTrayIcon::isSystemTrayAvailable())
00270 {
00271 exitCode = 1;
00272 break;
00273 }
00274 if (!initCheck())
00275 {
00276 exitCode = 1;
00277 break;
00278 }
00279 if (!displayTrayIcon(true))
00280 {
00281 exitCode = 1;
00282 break;
00283 }
00284 }
00285 else
00286 if (args->isSet("triggerEvent") || args->isSet("cancelEvent"))
00287 {
00288
00289 kDebug() << "Handle event";
00290 EventFunc function = EVENT_HANDLE;
00291 int count = 0;
00292 const char* option = 0;
00293 if (args->isSet("triggerEvent")) { function = EVENT_TRIGGER; option = "triggerEvent"; ++count; }
00294 if (args->isSet("cancelEvent")) { function = EVENT_CANCEL; option = "cancelEvent"; ++count; }
00295 if (count > 1)
00296 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--triggerEvent"), QLatin1String("--cancelEvent")));
00297 if (!initCheck(true))
00298 {
00299 exitCode = 1;
00300 break;
00301 }
00302 QString eventID = args->getOption(option);
00303 args->clear();
00304 startProcessQueue();
00305 if (!handleEvent(eventID, function))
00306 {
00307 exitCode = 1;
00308 break;
00309 }
00310 }
00311 else
00312 if (args->isSet("edit"))
00313 {
00314 QString eventID = args->getOption("edit");
00315 if (!initCheck())
00316 {
00317 exitCode = 1;
00318 break;
00319 }
00320 if (!KAlarm::editAlarm(eventID))
00321 {
00322 USAGE(i18nc("@info:shell", "<icode>%1</icode>: Event <resource>%2</resource> not found, or not editable", QString::fromLatin1("--edit"), eventID))
00323 exitCode = 1;
00324 break;
00325 }
00326 }
00327 else
00328 if (args->isSet("edit-new-display") || args->isSet("edit-new-command") || args->isSet("edit-new-email"))
00329 {
00330 EditAlarmDlg::Type type = args->isSet("edit-new-display") ? EditAlarmDlg::DISPLAY
00331 : args->isSet("edit-new-command") ? EditAlarmDlg::COMMAND
00332 : EditAlarmDlg::EMAIL;
00333 if (!initCheck())
00334 {
00335 exitCode = 1;
00336 break;
00337 }
00338 KAlarm::editNewAlarm(type);
00339 }
00340 else
00341 if (args->isSet("edit-new-preset"))
00342 {
00343 QString templ = args->getOption("edit-new-preset");
00344 if (!initCheck())
00345 {
00346 exitCode = 1;
00347 break;
00348 }
00349 KAlarm::editNewAlarm(templ);
00350 }
00351 else
00352 if (args->isSet("file") || args->isSet("exec") || args->isSet("exec-display") || args->isSet("mail") || args->count())
00353 {
00354
00355 KAEvent::Action action = KAEvent::MESSAGE;
00356 QString alMessage;
00357 uint alFromID;
00358 EmailAddressList alAddresses;
00359 QStringList alAttachments;
00360 QString alSubject;
00361 int flags = KAEvent::DEFAULT_FONT;
00362 if (args->isSet("file"))
00363 {
00364 kDebug() << "File";
00365 if (args->isSet("exec"))
00366 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--exec"), QLatin1String("--file")))
00367 if (args->isSet("mail"))
00368 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--mail"), QLatin1String("--file")))
00369 if (args->count())
00370 USAGE(i18nc("@info:shell", "message incompatible with <icode>%1</icode>", QLatin1String("--file")))
00371 alMessage = args->getOption("file");
00372 action = KAEvent::FILE;
00373 }
00374 else if (args->isSet("exec-display"))
00375 {
00376 kDebug() << "--exec-display";
00377 if (args->isSet("exec"))
00378 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--exec"), QLatin1String("--exec-display")))
00379 if (args->isSet("mail"))
00380 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--mail"), QLatin1String("--exec-display")))
00381 alMessage = args->getOption("exec-display");
00382 int n = args->count();
00383 for (int i = 0; i < n; ++i)
00384 {
00385 alMessage += ' ';
00386 alMessage += args->arg(i);
00387 }
00388 action = KAEvent::COMMAND;
00389 flags |= KAEvent::DISPLAY_COMMAND;
00390 }
00391 else if (args->isSet("exec"))
00392 {
00393 kDebug() << "--exec";
00394 if (args->isSet("mail"))
00395 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--mail"), QLatin1String("--exec")))
00396 alMessage = args->getOption("exec");
00397 int n = args->count();
00398 for (int i = 0; i < n; ++i)
00399 {
00400 alMessage += ' ';
00401 alMessage += args->arg(i);
00402 }
00403 action = KAEvent::COMMAND;
00404 }
00405 else if (args->isSet("mail"))
00406 {
00407 kDebug() << "--mail";
00408 if (args->isSet("subject"))
00409 alSubject = args->getOption("subject");
00410 if (args->isSet("from-id"))
00411 alFromID = KAMail::identityUoid(args->getOption("from-id"));
00412 QStringList params = args->getOptionList("mail");
00413 for (QStringList::Iterator i = params.begin(); i != params.end(); ++i)
00414 {
00415 QString addr = *i;
00416 if (!KAMail::checkAddress(addr))
00417 USAGE(i18nc("@info:shell", "<icode>%1</icode>: invalid email address", QLatin1String("--mail")))
00418 alAddresses += KCal::Person(QString(), addr);
00419 }
00420 params = args->getOptionList("attach");
00421 for (QStringList::Iterator i = params.begin(); i != params.end(); ++i)
00422 alAttachments += *i;
00423 alMessage = args->arg(0);
00424 action = KAEvent::EMAIL;
00425 }
00426 else
00427 {
00428 kDebug() << "Message";
00429 alMessage = args->arg(0);
00430 }
00431
00432 if (action != KAEvent::EMAIL)
00433 {
00434 if (args->isSet("subject"))
00435 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--subject"), QLatin1String("--mail")))
00436 if (args->isSet("from-id"))
00437 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--from-id"), QLatin1String("--mail")))
00438 if (args->isSet("attach"))
00439 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--attach"), QLatin1String("--mail")))
00440 if (args->isSet("bcc"))
00441 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--bcc"), QLatin1String("--mail")))
00442 }
00443
00444 KDateTime alarmTime, endTime;
00445 QColor bgColour = Preferences::defaultBgColour();
00446 QColor fgColour = Preferences::defaultFgColour();
00447 KARecurrence recurrence;
00448 int repeatCount = 0;
00449 int repeatInterval = 0;
00450 if (args->isSet("color"))
00451 {
00452
00453 QString colourText = args->getOption("color");
00454 if (colourText[0] == '0' && colourText[1].toLower() == 'x')
00455 colourText.replace(0, 2, "#");
00456 bgColour.setNamedColor(colourText);
00457 if (!bgColour.isValid())
00458 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("--color")))
00459 }
00460 if (args->isSet("colorfg"))
00461 {
00462
00463 QString colourText = args->getOption("colorfg");
00464 if (colourText[0] == '0' && colourText[1].toLower() == 'x')
00465 colourText.replace(0, 2, "#");
00466 fgColour.setNamedColor(colourText);
00467 if (!fgColour.isValid())
00468 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("--colorfg")))
00469 }
00470
00471 if (args->isSet("time"))
00472 {
00473 QByteArray dateTime = args->getOption("time").toLocal8Bit();
00474 if (!KAlarm::convTimeString(dateTime, alarmTime))
00475 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("--time")))
00476 }
00477 else
00478 alarmTime = KDateTime::currentLocalDateTime();
00479
00480 bool haveRecurrence = args->isSet("recurrence");
00481 if (haveRecurrence)
00482 {
00483 if (args->isSet("login"))
00484 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--login"), QLatin1String("--recurrence")))
00485 if (args->isSet("until"))
00486 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--until"), QLatin1String("--recurrence")))
00487 QString rule = args->getOption("recurrence");
00488 recurrence.set(rule);
00489 }
00490 if (args->isSet("interval"))
00491 {
00492
00493 int count;
00494 if (args->isSet("login"))
00495 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--login"), QLatin1String("--interval")))
00496 bool ok;
00497 if (args->isSet("repeat"))
00498 {
00499 count = args->getOption("repeat").toInt(&ok);
00500 if (!ok || !count || count < -1 || (count < 0 && haveRecurrence))
00501 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("--repeat")))
00502 }
00503 else if (haveRecurrence)
00504 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--interval"), QLatin1String("--repeat")))
00505 else if (args->isSet("until"))
00506 {
00507 count = 0;
00508 QByteArray dateTime = args->getOption("until").toLocal8Bit();
00509 bool ok;
00510 if (args->isSet("time"))
00511 ok = KAlarm::convTimeString(dateTime, endTime, alarmTime);
00512 else
00513 ok = KAlarm::convTimeString(dateTime, endTime);
00514 if (!ok)
00515 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("--until")))
00516 if (alarmTime.isDateOnly() && !endTime.isDateOnly())
00517 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter for date-only alarm", QLatin1String("--until")))
00518 if (!alarmTime.isDateOnly() && endTime.isDateOnly())
00519 endTime.setTime(QTime(23,59,59));
00520 if (endTime < alarmTime)
00521 USAGE(i18nc("@info:shell", "<icode>%1</icode> earlier than <icode>%2</icode>", QLatin1String("--until"), QLatin1String("--time")))
00522 }
00523 else
00524 count = -1;
00525
00526
00527 int interval;
00528 KARecurrence::Type recurType;
00529 if (!convInterval(args->getOption("interval").toLocal8Bit(), recurType, interval, !haveRecurrence)
00530 || interval < 0)
00531 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("--interval")))
00532 if (alarmTime.isDateOnly() && recurType == KARecurrence::MINUTELY)
00533 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter for date-only alarm", QLatin1String("--interval")))
00534
00535 if (haveRecurrence)
00536 {
00537
00538 int longestInterval = recurrence.longestInterval();
00539 if (count * interval > longestInterval)
00540 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> and <icode>%2</icode> parameters: repetition is longer than <icode>%3</icode> interval", QLatin1String("--interval"), QLatin1String("--repeat"), QLatin1String("--recurrence")));
00541 repeatCount = count;
00542 repeatInterval = interval;
00543 }
00544 else
00545 {
00546
00547
00548 recurrence.set(recurType, interval, count, alarmTime, endTime);
00549 }
00550 }
00551 else
00552 {
00553 if (args->isSet("repeat"))
00554 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--repeat"), QLatin1String("--interval")))
00555 if (args->isSet("until"))
00556 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--until"), QLatin1String("--interval")))
00557 }
00558
00559 QString audioFile;
00560 float audioVolume = -1;
00561 bool audioRepeat = args->isSet("play-repeat");
00562 if (audioRepeat || args->isSet("play"))
00563 {
00564
00565 if (audioRepeat && args->isSet("play"))
00566 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--play"), QLatin1String("--play-repeat")))
00567 if (args->isSet("beep"))
00568 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--beep"), QLatin1String(audioRepeat ? "--play-repeat" : "--play")))
00569 if (args->isSet("speak"))
00570 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--speak"), QLatin1String(audioRepeat ? "--play-repeat" : "--play")))
00571 audioFile = args->getOption(audioRepeat ? "play-repeat" : "play");
00572 if (args->isSet("volume"))
00573 {
00574 bool ok;
00575 int volumepc = args->getOption("volume").toInt(&ok);
00576 if (!ok || volumepc < 0 || volumepc > 100)
00577 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("--volume")))
00578 audioVolume = static_cast<float>(volumepc) / 100;
00579 }
00580 }
00581 else if (args->isSet("volume"))
00582 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode> or <icode>%3</icode>", QLatin1String("--volume"), QLatin1String("--play"), QLatin1String("--play-repeat")))
00583 if (args->isSet("speak"))
00584 {
00585 if (args->isSet("beep"))
00586 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--beep"), QLatin1String("--speak")))
00587 if (!mSpeechEnabled)
00588 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires speech synthesis to be configured using KTTSD", QLatin1String("--speak")))
00589 }
00590 int reminderMinutes = 0;
00591 bool onceOnly = args->isSet("reminder-once");
00592 if (args->isSet("reminder") || onceOnly)
00593 {
00594
00595 if (onceOnly && args->isSet("reminder"))
00596 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", QLatin1String("--reminder"), QLatin1String("--reminder-once")))
00597 QString opt = onceOnly ? QLatin1String("--reminder-once") : QLatin1String("--reminder");
00598 if (args->isSet("exec"))
00599 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", opt, QLatin1String("--exec")))
00600 if (args->isSet("mail"))
00601 USAGE(i18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", opt, QLatin1String("--mail")))
00602 KARecurrence::Type recurType;
00603 QString optval = args->getOption(onceOnly ? "reminder-once" : "reminder");
00604 if (!convInterval(args->getOption(onceOnly ? "reminder-once" : "reminder").toLocal8Bit(), recurType, reminderMinutes))
00605 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", opt))
00606 if (recurType == KARecurrence::MINUTELY && alarmTime.isDateOnly())
00607 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter for date-only alarm", opt))
00608 }
00609
00610 int lateCancel = 0;
00611 if (args->isSet("late-cancel"))
00612 {
00613 KARecurrence::Type recurType;
00614 bool ok = convInterval(args->getOption("late-cancel").toLocal8Bit(), recurType, lateCancel);
00615 if (!ok || lateCancel <= 0)
00616 USAGE(i18nc("@info:shell", "Invalid <icode>%1</icode> parameter", QLatin1String("late-cancel")))
00617 }
00618 else if (args->isSet("auto-close"))
00619 USAGE(i18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", QLatin1String("--auto-close"), QLatin1String("--late-cancel")))
00620
00621 if (args->isSet("ack-confirm"))
00622 flags |= KAEvent::CONFIRM_ACK;
00623 if (args->isSet("auto-close"))
00624 flags |= KAEvent::AUTO_CLOSE;
00625 if (args->isSet("beep"))
00626 flags |= KAEvent::BEEP;
00627 if (args->isSet("speak"))
00628 flags |= KAEvent::SPEAK;
00629 if (args->isSet("korganizer"))
00630 flags |= KAEvent::COPY_KORGANIZER;
00631 if (args->isSet("disable"))
00632 flags |= KAEvent::DISABLED;
00633 if (audioRepeat)
00634 flags |= KAEvent::REPEAT_SOUND;
00635 if (args->isSet("login"))
00636 flags |= KAEvent::REPEAT_AT_LOGIN;
00637 if (args->isSet("bcc"))
00638 flags |= KAEvent::EMAIL_BCC;
00639 if (alarmTime.isDateOnly())
00640 flags |= KAEvent::ANY_TIME;
00641 args->clear();
00642
00643
00644 if (!initCheck())
00645 {
00646 exitCode = 1;
00647 break;
00648 }
00649 if (!scheduleEvent(action, alMessage, alarmTime, lateCancel, flags, bgColour, fgColour, QFont(), audioFile,
00650 audioVolume, reminderMinutes, recurrence, repeatInterval, repeatCount,
00651 alFromID, alAddresses, alSubject, alAttachments))
00652 {
00653 exitCode = 1;
00654 break;
00655 }
00656 }
00657 else
00658 {
00659
00660 kDebug() << "Interactive";
00661 if (args->isSet("ack-confirm"))
00662 usage += QLatin1String("--ack-confirm ");
00663 if (args->isSet("attach"))
00664 usage += QLatin1String("--attach ");
00665 if (args->isSet("auto-close"))
00666 usage += QLatin1String("--auto-close ");
00667 if (args->isSet("bcc"))
00668 usage += QLatin1String("--bcc ");
00669 if (args->isSet("beep"))
00670 usage += QLatin1String("--beep ");
00671 if (args->isSet("color"))
00672 usage += QLatin1String("--color ");
00673 if (args->isSet("colorfg"))
00674 usage += QLatin1String("--colorfg ");
00675 if (args->isSet("disable"))
00676 usage += QLatin1String("--disable ");
00677 if (args->isSet("from-id"))
00678 usage += QLatin1String("--from-id ");
00679 if (args->isSet("korganizer"))
00680 usage += QLatin1String("--korganizer ");
00681 if (args->isSet("late-cancel"))
00682 usage += QLatin1String("--late-cancel ");
00683 if (args->isSet("login"))
00684 usage += QLatin1String("--login ");
00685 if (args->isSet("play"))
00686 usage += QLatin1String("--play ");
00687 if (args->isSet("play-repeat"))
00688 usage += QLatin1String("--play-repeat ");
00689 if (args->isSet("reminder"))
00690 usage += QLatin1String("--reminder ");
00691 if (args->isSet("reminder-once"))
00692 usage += QLatin1String("--reminder-once ");
00693 if (args->isSet("speak"))
00694 usage += QLatin1String("--speak ");
00695 if (args->isSet("subject"))
00696 usage += QLatin1String("--subject ");
00697 if (args->isSet("time"))
00698 usage += QLatin1String("--time ");
00699 if (args->isSet("volume"))
00700 usage += QLatin1String("--volume ");
00701 if (!usage.isEmpty())
00702 {
00703 usage += i18nc("@info:shell", ": option(s) only valid with a message/<icode>%1</icode>/<icode>%2</icode>", QLatin1String("--file"), QLatin1String("--exec"));
00704 break;
00705 }
00706
00707 args->clear();
00708 if (!initCheck())
00709 {
00710 exitCode = 1;
00711 break;
00712 }
00713
00714 (MainWindow::create())->show();
00715 }
00716 } while (0);
00717
00718 if (!usage.isEmpty())
00719 {
00720
00721
00722 std::cerr << usage.toLocal8Bit().data()
00723 << i18nc("@info:shell", "\nUse --help to get a list of available command line options.\n").toLocal8Bit().data();
00724 exitCode = 1;
00725 }
00726 }
00727 if (firstInstance && !dontRedisplay && !exitCode)
00728 MessageWin::redisplayAlarms();
00729
00730 --mActiveCount;
00731 firstInstance = false;
00732
00733
00734
00735
00736 quitIf(exitCode);
00737 return exitCode;
00738 }
00739
00740
00741
00742
00743 void KAlarmApp::quitIf(int exitCode, bool force)
00744 {
00745 if (force)
00746 {
00747
00748 mQuitting = true;
00749 MainWindow::closeAll();
00750 displayTrayIcon(false);
00751 if (MessageWin::instanceCount())
00752 return;
00753 }
00754 else if (mQuitting)
00755 return;
00756 else
00757 {
00758
00759 mPendingQuit = false;
00760 if (mActiveCount > 0 || MessageWin::instanceCount())
00761 return;
00762 int mwcount = MainWindow::count();
00763 MainWindow* mw = mwcount ? MainWindow::firstWindow() : 0;
00764 if (mwcount > 1 || (mwcount && (!mw->isHidden() || !mw->isTrayParent())))
00765 return;
00766
00767 if (mTrayWindow)
00768 {
00769
00770
00771 if (checkSystemTray())
00772 return;
00773 }
00774 if (!mDcopQueue.isEmpty() || !mCommandProcesses.isEmpty())
00775 {
00776
00777 mPendingQuit = true;
00778 mPendingQuitCode = exitCode;
00779 return;
00780 }
00781 }
00782
00783
00784 kDebug() << exitCode << ": quitting";
00785 AlarmCalendar::terminateCalendars();
00786 BirthdayModel::close();
00787 exit(exitCode);
00788 }
00789
00790
00791
00792
00793
00794
00795 void KAlarmApp::doQuit(QWidget* parent)
00796 {
00797 kDebug();
00798 if (MessageBox::warningContinueCancel(parent, KMessageBox::Cancel,
00799 i18nc("@info", "Quitting will disable alarms (once any alarm message windows are closed)."),
00800 QString(), KStandardGuiItem::quit(), Preferences::QUIT_WARN
00801 ) != KMessageBox::Yes)
00802 return;
00803 quitIf(0, true);
00804 }
00805
00806
00807
00808
00809 void KAlarmApp::commitData(QSessionManager& sm)
00810 {
00811 mSessionClosingDown = true;
00812 KUniqueApplication::commitData(sm);
00813 mSessionClosingDown = false;
00814 }
00815
00816
00817
00818
00819
00820 void KAlarmApp::displayFatalError(const QString& message)
00821 {
00822 if (!mFatalError)
00823 {
00824 mFatalError = 1;
00825 mFatalMessage = message;
00826 if (theInstance)
00827 QTimer::singleShot(0, theInstance, SLOT(quitFatal()));
00828 }
00829 }
00830
00831
00832
00833
00834 void KAlarmApp::quitFatal()
00835 {
00836 switch (mFatalError)
00837 {
00838 case 0:
00839 case 2:
00840 return;
00841 case 1:
00842 mFatalError = 2;
00843 KMessageBox::error(0, mFatalMessage);
00844 mFatalError = 3;
00845
00846 case 3:
00847 if (theInstance)
00848 theInstance->quitIf(1, true);
00849 break;
00850 }
00851 QTimer::singleShot(1000, this, SLOT(quitFatal()));
00852 }
00853
00854
00855
00856
00857
00858
00859 void KAlarmApp::checkNextDueAlarm()
00860 {
00861 if (!mAlarmsEnabled)
00862 return;
00863
00864 KAEvent* nextEvent = AlarmCalendar::resources()->earliestAlarm();
00865 if (!nextEvent)
00866 return;
00867 KDateTime nextDt = nextEvent->nextTrigger(KAEvent::ALL_TRIGGER).effectiveKDateTime();
00868 qint64 interval = KDateTime::currentDateTime(Preferences::timeZone()).secsTo_long(nextDt);
00869 if (interval <= 0)
00870 {
00871
00872 queueAlarmId(nextEvent->id());
00873 kDebug() << nextEvent->id() << ": due now";
00874 QTimer::singleShot(0, this, SLOT(processQueue()));
00875 }
00876 else
00877 {
00878
00879
00880 interval *= 1000;
00881 if (interval > INT_MAX)
00882 interval = INT_MAX;
00883 kDebug() << nextEvent->id() << "wait" << interval/1000 << "seconds";
00884 mAlarmTimer->start(static_cast<int>(interval));
00885 }
00886 }
00887
00888
00889
00890
00891
00892
00893 void KAlarmApp::queueAlarmId(const QString& id)
00894 {
00895 for (int i = 0, end = mDcopQueue.count(); i < end; ++i)
00896 {
00897 if (mDcopQueue[i].function == EVENT_HANDLE && mDcopQueue[i].eventId