2 * commandoptions.cpp - extract command line options
4 * Copyright © 2001-2016 by David Jarvie <djarvie@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
22 #include "commandoptions.h"
23 #include "alarmtime.h"
24 #include "kalarmapp.h"
26 #include "kalarm_debug.h"
28 #include <kalarmcal/identities.h>
29 #include <kpimtextedit/texttospeech.h>
30 #include <KLocalizedString>
32 #include <QCommandLineParser>
38 bool convInterval(const QString
& timeParam
, KARecurrence::Type
&, int& timeInterval
, bool allowMonthYear
= false);
41 CommandOptions
* CommandOptions::mInstance
= Q_NULLPTR
;
42 QCommandLineParser
* CommandOptions::mParser
= Q_NULLPTR
;
43 QVector
<QCommandLineOption
*> CommandOptions::mOptions(Num_Options
, Q_NULLPTR
);
44 QStringList
CommandOptions::mExecArguments
;
46 void CommandOptions::setError(const QString
& error
)
52 /******************************************************************************
53 * Set the command line options for the parser, and remove any arguments
54 * following --exec or --exec-display (since the parser can't handle this).
55 * Reply = command line arguments for parser.
57 QStringList
CommandOptions::setOptions(QCommandLineParser
* parser
, const QStringList
& args
)
62 = new QCommandLineOption(QStringList() << QStringLiteral("a") << QStringLiteral("ack-confirm"),
63 i18n("Prompt for confirmation when alarm is acknowledged"));
65 = new QCommandLineOption(QStringList() << QStringLiteral("A") << QStringLiteral("attach"),
66 i18n("Attach file to email (repeat as needed)"),
67 QStringLiteral("url"));
69 = new QCommandLineOption(QStringLiteral("auto-close"),
70 i18n("Auto-close alarm window after --late-cancel period"));
72 = new QCommandLineOption(QStringLiteral("bcc"),
73 i18n("Blind copy email to self"));
75 = new QCommandLineOption(QStringList() << QStringLiteral("b") << QStringLiteral("beep"),
76 i18n("Beep when message is displayed"));
78 = new QCommandLineOption(QStringList() << QStringLiteral("c") << QStringLiteral("colour") << QStringLiteral("color"),
79 i18n("Message background color (name or hex 0xRRGGBB)"),
80 QStringLiteral("color"));
82 = new QCommandLineOption(QStringList() << QStringLiteral("C") << QStringLiteral("colourfg") << QStringLiteral("colorfg"),
83 i18n("Message foreground color (name or hex 0xRRGGBB)"),
84 QStringLiteral("color"));
85 mOptions
[OptCANCEL_EVENT
]
86 = new QCommandLineOption(QStringLiteral("cancelEvent"),
87 i18n("Cancel alarm with the specified event ID"),
88 QStringLiteral("eventID"));
90 = new QCommandLineOption(QStringList() << QStringLiteral("d") << QStringLiteral("disable"),
91 i18n("Disable the alarm"));
93 = new QCommandLineOption(QStringLiteral("disable-all"),
94 i18n("Disable monitoring of all alarms"));
96 = new QCommandLineOption(QStringList() << QStringLiteral("e") << QStringLiteral("exec"),
97 i18n("Execute a shell command line"),
98 QStringLiteral("commandLine"));
99 mOptions
[EXEC_DISPLAY
]
100 = new QCommandLineOption(QStringList() << QStringLiteral("E") << QStringLiteral("exec-display"),
101 i18n("Command line to generate alarm message text"),
102 QStringLiteral("commandLine"));
104 = new QCommandLineOption(QStringLiteral("edit"),
105 i18n("Display the alarm edit dialog to edit the specified alarm"),
106 QStringLiteral("eventID"));
107 mOptions
[EDIT_NEW_DISPLAY
]
108 = new QCommandLineOption(QStringLiteral("edit-new-display"),
109 i18n("Display the alarm edit dialog to edit a new display alarm"));
110 mOptions
[EDIT_NEW_COMMAND
]
111 = new QCommandLineOption(QStringLiteral("edit-new-command"),
112 i18n("Display the alarm edit dialog to edit a new command alarm"));
113 mOptions
[EDIT_NEW_EMAIL
]
114 = new QCommandLineOption(QStringLiteral("edit-new-email"),
115 i18n("Display the alarm edit dialog to edit a new email alarm"));
116 mOptions
[EDIT_NEW_AUDIO
]
117 = new QCommandLineOption(QStringLiteral("edit-new-audio"),
118 i18n("Display the alarm edit dialog to edit a new audio alarm"));
119 mOptions
[OptEDIT_NEW_PRESET
]
120 = new QCommandLineOption(QStringLiteral("edit-new-preset"),
121 i18n("Display the alarm edit dialog, preset with a template"),
122 QStringLiteral("templateName"));
124 = new QCommandLineOption(QStringList() << QStringLiteral("f") << QStringLiteral("file"),
125 i18n("File to display"),
126 QStringLiteral("url"));
128 = new QCommandLineOption(QStringList() << QStringLiteral("F") << QStringLiteral("from-id"),
129 i18n("KMail identity to use as sender of email"),
130 QStringLiteral("ID"));
132 = new QCommandLineOption(QStringList() << QStringLiteral("i") << QStringLiteral("interval"),
133 i18n("Interval between alarm repetitions"),
134 QStringLiteral("period"));
136 = new QCommandLineOption(QStringList() << QStringLiteral("k") << QStringLiteral("korganizer"),
137 i18n("Show alarm as an event in KOrganizer"));
138 mOptions
[LATE_CANCEL
]
139 = new QCommandLineOption(QStringList() << QStringLiteral("l") << QStringLiteral("late-cancel"),
140 i18n("Cancel alarm if more than 'period' late when triggered"),
141 QStringLiteral("period"),
142 QStringLiteral("1"));
144 = new QCommandLineOption(QStringLiteral("list"),
145 i18n("Output list of scheduled alarms to stdout"));
147 = new QCommandLineOption(QStringList() << QStringLiteral("L") << QStringLiteral("login"),
148 i18n("Repeat alarm at every login"));
150 = new QCommandLineOption(QStringList() << QStringLiteral("m") << QStringLiteral("mail"),
151 i18n("Send an email to the given address (repeat as needed)"),
152 QStringLiteral("address"));
154 = new QCommandLineOption(QStringList() << QStringLiteral("p") << QStringLiteral("play"),
155 i18n("Audio file to play once"),
156 QStringLiteral("url"));
157 mOptions
[PLAY_REPEAT
]
158 = new QCommandLineOption(QStringList() << QStringLiteral("P") << QStringLiteral("play-repeat"),
159 i18n("Audio file to play repeatedly"),
160 QStringLiteral("url"));
162 = new QCommandLineOption(QStringLiteral("recurrence"),
163 i18n("Specify alarm recurrence using iCalendar syntax"),
164 QStringLiteral("spec"));
166 = new QCommandLineOption(QStringList() << QStringLiteral("R") << QStringLiteral("reminder"),
167 i18n("Display reminder before or after alarm"),
168 QStringLiteral("period"));
169 mOptions
[REMINDER_ONCE
]
170 = new QCommandLineOption(QStringLiteral("reminder-once"),
171 i18n("Display reminder once, before or after first alarm recurrence"),
172 QStringLiteral("period"));
174 = new QCommandLineOption(QStringList() << QStringLiteral("r") << QStringLiteral("repeat"),
175 i18n("Number of times to repeat alarm (including initial occasion)"),
176 QStringLiteral("count"));
178 = new QCommandLineOption(QStringList() << QStringLiteral("s") << QStringLiteral("speak"),
179 i18n("Speak the message when it is displayed"));
181 = new QCommandLineOption(QStringList() << QStringLiteral("S") << QStringLiteral("subject"),
182 i18n("Email subject line"),
183 QStringLiteral("text"));
185 mOptions
[TEST_SET_TIME
]
186 = new QCommandLineOption(QStringLiteral("test-set-time"),
187 i18n("Simulate system time [[[yyyy-]mm-]dd-]hh:mm [TZ] (debug mode)"),
188 QStringLiteral("time"));
191 = new QCommandLineOption(QStringList() << QStringLiteral("t") << QStringLiteral("time"),
192 i18n("Trigger alarm at time [[[yyyy-]mm-]dd-]hh:mm [TZ], or date yyyy-mm-dd [TZ]"),
193 QStringLiteral("time"));
195 = new QCommandLineOption(QStringLiteral("tray"),
196 i18n("Display system tray icon"));
197 mOptions
[OptTRIGGER_EVENT
]
198 = new QCommandLineOption(QStringLiteral("triggerEvent"),
199 i18n("Trigger alarm with the specified event ID"),
200 QStringLiteral("eventID"));
202 = new QCommandLineOption(QStringList() << QStringLiteral("u") << QStringLiteral("until"),
203 i18n("Repeat until time [[[yyyy-]mm-]dd-]hh:mm [TZ], or date yyyy-mm-dd [TZ]"),
204 QStringLiteral("time"));
206 = new QCommandLineOption(QStringList() << QStringLiteral("V") << QStringLiteral("volume"),
207 i18n("Volume to play audio file"),
208 QStringLiteral("percent"));
210 for (int i
= 0; i
< mOptions
.size(); ++i
)
213 qCCritical(KALARM_LOG
) << "Command option" << i
<< "not initialised";
215 mParser
->addOption(*(mOptions
[i
]));
217 mParser
->addVersionOption();
218 mParser
->addHelpOption();
219 mParser
->addPositionalArgument(QStringLiteral("message"),
220 i18n("Message text to display"),
221 QStringLiteral("[message]"));
223 // Check for any options which eat up all following arguments.
224 QStringList arguments
;
225 for (int i
= 0; i
< args
.size(); ++i
)
227 const QString arg
= args
[i
];
229 if (arg
== optionName(EXEC
) || arg
== optionName(EXEC
, true)
230 || arg
== optionName(EXEC_DISPLAY
) || arg
== optionName(EXEC_DISPLAY
, true))
232 // All following arguments (including ones beginning with '-')
233 // belong to this option. QCommandLineParser can't handle this, so
234 // remove them from the command line.
235 ++i
; // leave the first argument, which is the command to be executed
236 while (++i
< args
.size())
237 mExecArguments
<< args
[i
];
240 qCDebug(KALARM_LOG
) << arguments
;
244 void CommandOptions::process()
247 mInstance
= new CommandOptions();
250 CommandOptions::CommandOptions()
252 mEditActionSet(false),
253 mRecurrence(Q_NULLPTR
),
257 mBgColour(Preferences::defaultBgColour()),
258 mFgColour(Preferences::defaultFgColour()),
262 mFlags(KAEvent::DEFAULT_FONT
),
266 if (mParser
->isSet(*mOptions
[TEST_SET_TIME
]))
268 const QString time
= mParser
->value(*mOptions
[TEST_SET_TIME
]);
269 if (!AlarmTime::convertTimeString(time
.toLatin1(), mSimulationTime
, KDateTime::realCurrentLocalDateTime(), true))
270 setErrorParameter(TEST_SET_TIME
);
273 if (checkCommand(OptTRAY
, TRAY
))
276 if (checkCommand(OptLIST
, LIST
))
278 if (!mParser
->positionalArguments().empty())
279 setErrorParameter(OptLIST
);
281 if (checkCommand(OptTRIGGER_EVENT
, TRIGGER_EVENT
)
282 || checkCommand(OptCANCEL_EVENT
, CANCEL_EVENT
)
283 || checkCommand(OptEDIT
, EDIT
))
285 // Fetch the event ID. This can optionally include a prefix of the
286 // resource ID followed by a colon delimiter.
287 mEventId
= EventId(mParser
->value(*mOptions
[mCommandOpt
]));
289 if (checkCommand(OptEDIT_NEW_PRESET
, EDIT_NEW_PRESET
))
291 mTemplateName
= mParser
->value(*mOptions
[mCommandOpt
]);
293 if (checkCommand(FILE, NEW
))
295 mEditType
= EditAlarmDlg::DISPLAY
;
296 mEditAction
= KAEvent::FILE;
297 mEditActionSet
= true;
298 mText
= mParser
->value(*mOptions
[mCommandOpt
]);
300 if (checkCommand(EXEC_DISPLAY
, NEW
))
302 mEditType
= EditAlarmDlg::DISPLAY
;
303 mEditAction
= KAEvent::COMMAND
;
304 mEditActionSet
= true;
305 mFlags
|= KAEvent::DISPLAY_COMMAND
;
306 mText
= mParser
->value(*mOptions
[mCommandOpt
]) + QStringLiteral(" ") + mExecArguments
.join(QLatin1Char(' '));
308 if (checkCommand(EXEC
, NEW
))
310 mEditType
= EditAlarmDlg::COMMAND
;
311 mEditAction
= KAEvent::COMMAND
;
312 mEditActionSet
= true;
313 mText
= mParser
->value(*mOptions
[mCommandOpt
]) + QStringLiteral(" ") + mExecArguments
.join(QLatin1Char(' '));
315 if (checkCommand(MAIL
, NEW
))
317 mEditType
= EditAlarmDlg::EMAIL
;
318 mEditAction
= KAEvent::EMAIL
;
319 mEditActionSet
= true;
321 if (checkCommand(EDIT_NEW_DISPLAY
, EDIT_NEW
, EditAlarmDlg::DISPLAY
))
323 mEditType
= EditAlarmDlg::DISPLAY
;
324 if (!mEditActionSet
|| (mEditAction
!= KAEvent::COMMAND
&& mEditAction
!= KAEvent::FILE))
326 mEditAction
= KAEvent::MESSAGE
;
327 mEditActionSet
= true;
329 const QStringList args
= mParser
->positionalArguments();
333 if (checkCommand(EDIT_NEW_COMMAND
, EDIT_NEW
))
335 mEditType
= EditAlarmDlg::COMMAND
;
336 mEditAction
= KAEvent::COMMAND
;
337 mEditActionSet
= true;
339 if (checkCommand(EDIT_NEW_EMAIL
, EDIT_NEW
, EditAlarmDlg::EMAIL
))
341 mEditType
= EditAlarmDlg::EMAIL
;
342 mEditAction
= KAEvent::EMAIL
;
343 mEditActionSet
= true;
345 if (checkCommand(EDIT_NEW_AUDIO
, EDIT_NEW
, EditAlarmDlg::AUDIO
))
347 mEditType
= EditAlarmDlg::AUDIO
;
348 mEditAction
= KAEvent::AUDIO
;
349 mEditActionSet
= true;
351 if (mError
.isEmpty() && mCommand
== NONE
)
353 if (mParser
->positionalArguments().empty())
355 if (checkCommand(PLAY
, NEW
) || checkCommand(PLAY_REPEAT
, NEW
))
357 mEditType
= EditAlarmDlg::AUDIO
;
358 mEditAction
= KAEvent::AUDIO
;
359 mEditActionSet
= true;
364 qCDebug(KALARM_LOG
) << "Message";
366 mCommandOpt
= Opt_Message
;
367 mEditType
= EditAlarmDlg::DISPLAY
;
368 mEditAction
= KAEvent::MESSAGE
;
369 mEditActionSet
= true;
373 if (mEditActionSet
&& mEditAction
== KAEvent::EMAIL
)
375 if (mParser
->isSet(*mOptions
[SUBJECT
]))
376 mSubject
= mParser
->value(*mOptions
[SUBJECT
]);
377 if (mParser
->isSet(*mOptions
[FROM_ID
]))
378 mFromID
= Identities::identityUoid(mParser
->value(*mOptions
[FROM_ID
]));
379 QStringList params
= mParser
->values(*mOptions
[MAIL
]);
380 for (int i
= 0, count
= params
.count(); i
< count
; ++i
)
382 QString addr
= params
[i
];
383 if (!KAMail::checkAddress(addr
))
384 setError(xi18nc("@info:shell", "<icode>%1</icode>: invalid email address", optionName(MAIL
)));
385 KCalCore::Person::Ptr
person(new KCalCore::Person(QString(), addr
));
386 mAddressees
+= person
;
388 params
= mParser
->values(*mOptions
[ATTACH
]);
389 for (int i
= 0, count
= params
.count(); i
< count
; ++i
)
390 mAttachments
+= params
[i
];
391 const QStringList args
= mParser
->positionalArguments();
395 if (mParser
->isSet(*mOptions
[DISABLE_ALL
]))
397 if (mCommand
== TRIGGER_EVENT
|| mCommand
== LIST
)
398 setErrorIncompatible(DISABLE_ALL
, mCommandOpt
);
402 // Check that other options are only specified for the
403 // correct main command options.
404 checkEditType(EditAlarmDlg::DISPLAY
, COLOUR
);
405 checkEditType(EditAlarmDlg::DISPLAY
, COLOURFG
);
406 checkEditType(EditAlarmDlg::DISPLAY
, EditAlarmDlg::AUDIO
, PLAY
);
407 checkEditType(EditAlarmDlg::DISPLAY
, EditAlarmDlg::AUDIO
, PLAY_REPEAT
);
408 checkEditType(EditAlarmDlg::DISPLAY
, EditAlarmDlg::AUDIO
, VOLUME
);
409 checkEditType(EditAlarmDlg::DISPLAY
, SPEAK
);
410 checkEditType(EditAlarmDlg::DISPLAY
, BEEP
);
411 checkEditType(EditAlarmDlg::DISPLAY
, REMINDER
);
412 checkEditType(EditAlarmDlg::DISPLAY
, REMINDER_ONCE
);
413 checkEditType(EditAlarmDlg::DISPLAY
, ACK_CONFIRM
);
414 checkEditType(EditAlarmDlg::DISPLAY
, AUTO_CLOSE
);
415 checkEditType(EditAlarmDlg::EMAIL
, SUBJECT
);
416 checkEditType(EditAlarmDlg::EMAIL
, FROM_ID
);
417 checkEditType(EditAlarmDlg::EMAIL
, ATTACH
);
418 checkEditType(EditAlarmDlg::EMAIL
, BCC
);
423 if (mParser
->isSet(*mOptions
[DISABLE
]))
424 setErrorIncompatible(DISABLE
, mCommandOpt
);
425 // Fall through to NEW
428 // Display a message or file, execute a command, or send an email
429 if (mParser
->isSet(*mOptions
[COLOUR
]))
431 // Background colour is specified
432 QString colourText
= mParser
->value(*mOptions
[COLOUR
]);
433 if (colourText
[0] == QLatin1Char('0') && colourText
[1].toLower() == QLatin1Char('x'))
434 colourText
.replace(0, 2, QStringLiteral("#"));
435 mBgColour
.setNamedColor(colourText
);
436 if (!mBgColour
.isValid())
437 setErrorParameter(COLOUR
);
439 if (mParser
->isSet(*mOptions
[COLOURFG
]))
441 // Foreground colour is specified
442 QString colourText
= mParser
->value(*mOptions
[COLOURFG
]);
443 if (colourText
[0] == QLatin1Char('0') && colourText
[1].toLower() == QLatin1Char('x'))
444 colourText
.replace(0, 2, QStringLiteral("#"));
445 mFgColour
.setNamedColor(colourText
);
446 if (!mFgColour
.isValid())
447 setErrorParameter(COLOURFG
);
450 if (mParser
->isSet(*mOptions
[TIME
]))
452 QByteArray dateTime
= mParser
->value(*mOptions
[TIME
]).toLocal8Bit();
453 if (!AlarmTime::convertTimeString(dateTime
, mAlarmTime
))
454 setErrorParameter(TIME
);
457 mAlarmTime
= KDateTime::currentLocalDateTime();
459 bool haveRecurrence
= mParser
->isSet(*mOptions
[RECURRENCE
]);
462 if (mParser
->isSet(*mOptions
[LOGIN
]))
463 setErrorIncompatible(LOGIN
, RECURRENCE
);
464 else if (mParser
->isSet(*mOptions
[UNTIL
]))
465 setErrorIncompatible(UNTIL
, RECURRENCE
);
466 QString rule
= mParser
->value(*mOptions
[RECURRENCE
]);
467 mRecurrence
= new KARecurrence
;
468 mRecurrence
->set(rule
);
470 if (mParser
->isSet(*mOptions
[INTERVAL
]))
472 // Repeat count is specified
475 if (mParser
->isSet(*mOptions
[LOGIN
]))
476 setErrorIncompatible(LOGIN
, INTERVAL
);
478 if (mParser
->isSet(*mOptions
[REPEAT
]))
480 count
= mParser
->value(*mOptions
[REPEAT
]).toInt(&ok
);
481 if (!ok
|| !count
|| count
< -1 || (count
< 0 && haveRecurrence
))
482 setErrorParameter(REPEAT
);
484 else if (haveRecurrence
)
485 setErrorRequires(INTERVAL
, REPEAT
);
486 else if (mParser
->isSet(*mOptions
[UNTIL
]))
489 QByteArray dateTime
= mParser
->value(*mOptions
[UNTIL
]).toLocal8Bit();
491 if (mParser
->isSet(*mOptions
[TIME
]))
492 ok
= AlarmTime::convertTimeString(dateTime
, endTime
, mAlarmTime
);
494 ok
= AlarmTime::convertTimeString(dateTime
, endTime
);
496 setErrorParameter(UNTIL
);
497 else if (mAlarmTime
.isDateOnly() && !endTime
.isDateOnly())
498 setError(xi18nc("@info:shell", "Invalid <icode>%1</icode> parameter for date-only alarm", optionName(UNTIL
)));
499 if (!mAlarmTime
.isDateOnly() && endTime
.isDateOnly())
500 endTime
.setTime(QTime(23,59,59));
501 if (endTime
< mAlarmTime
)
502 setError(xi18nc("@info:shell", "<icode>%1</icode> earlier than <icode>%2</icode>", optionName(UNTIL
), optionName(TIME
)));
507 // Get the recurrence interval
509 KARecurrence::Type recurType
;
510 if (!convInterval(mParser
->value(*mOptions
[INTERVAL
]), recurType
, intervalOfType
, !haveRecurrence
))
511 setErrorParameter(INTERVAL
);
512 else if (mAlarmTime
.isDateOnly() && recurType
== KARecurrence::MINUTELY
)
513 setError(xi18nc("@info:shell", "Invalid <icode>%1</icode> parameter for date-only alarm", optionName(INTERVAL
)));
519 // There is a also a recurrence specified, so set up a sub-repetition.
520 // In this case, 'intervalOfType' is in minutes.
521 mRepeatInterval
= KCalCore::Duration(intervalOfType
* 60);
522 KCalCore::Duration longestInterval
= mRecurrence
->longestInterval();
523 if (mRepeatInterval
* count
> longestInterval
)
524 setError(xi18nc("@info:shell", "Invalid <icode>%1</icode> and <icode>%2</icode> parameters: repetition is longer than <icode>%3</icode> interval",
525 optionName(INTERVAL
), optionName(REPEAT
), optionName(RECURRENCE
)));
526 mRepeatCount
= count
;
531 // There is no other recurrence specified, so convert the repetition
532 // parameters into a KCal::Recurrence
533 mRecurrence
= new KARecurrence
;
534 mRecurrence
->set(recurType
, intervalOfType
, count
, mAlarmTime
, endTime
);
539 if (mParser
->isSet(*mOptions
[REPEAT
]))
540 setErrorRequires(REPEAT
, INTERVAL
);
541 else if (mParser
->isSet(*mOptions
[UNTIL
]))
542 setErrorRequires(UNTIL
, INTERVAL
);
545 bool audioRepeat
= mParser
->isSet(*mOptions
[PLAY_REPEAT
]);
546 if (audioRepeat
|| mParser
->isSet(*mOptions
[PLAY
]))
548 // Play a sound with the alarm
549 Option opt
= audioRepeat
? PLAY_REPEAT
: PLAY
;
550 if (audioRepeat
&& mParser
->isSet(*mOptions
[PLAY
]))
551 setErrorIncompatible(PLAY
, PLAY_REPEAT
);
552 if (mParser
->isSet(*mOptions
[BEEP
]))
553 setErrorIncompatible(BEEP
, opt
);
554 else if (mParser
->isSet(*mOptions
[SPEAK
]))
555 setErrorIncompatible(SPEAK
, opt
);
556 mAudioFile
= mParser
->value(*mOptions
[audioRepeat
? PLAY_REPEAT
: PLAY
]);
557 if (mParser
->isSet(*mOptions
[VOLUME
]))
560 int volumepc
= mParser
->value(*mOptions
[VOLUME
]).toInt(&ok
);
561 if (!ok
|| volumepc
< 0 || volumepc
> 100)
562 setErrorParameter(VOLUME
);
563 mAudioVolume
= static_cast<float>(volumepc
) / 100;
566 else if (mParser
->isSet(*mOptions
[VOLUME
]))
567 setErrorRequires(VOLUME
, PLAY
, PLAY_REPEAT
);
568 if (mParser
->isSet(*mOptions
[SPEAK
]))
570 if (mParser
->isSet(*mOptions
[BEEP
]))
571 setErrorIncompatible(BEEP
, SPEAK
);
572 else if (!KPIMTextEdit::TextToSpeech::self()->isReady())
573 setError(xi18nc("@info:shell", "<icode>%1</icode> requires KAlarm to be compiled with QTextToSpeech support", optionName(SPEAK
)));
575 bool onceOnly
= mParser
->isSet(*mOptions
[REMINDER_ONCE
]);
576 if (mParser
->isSet(*mOptions
[REMINDER
]) || onceOnly
)
578 // Issue a reminder alarm in advance of or after the main alarm
579 if (onceOnly
&& mParser
->isSet(*mOptions
[REMINDER
]))
580 setErrorIncompatible(REMINDER
, REMINDER_ONCE
);
581 Option opt
= onceOnly
? REMINDER_ONCE
: REMINDER
;
582 KARecurrence::Type recurType
;
583 QString optval
= mParser
->value(*mOptions
[onceOnly
? REMINDER_ONCE
: REMINDER
]);
584 bool after
= (optval
[0] == QLatin1Char('+'));
586 optval
.remove(0, 1); // it's a reminder after the main alarm
587 if (!convInterval(optval
, recurType
, mReminderMinutes
))
588 setErrorParameter(opt
);
589 else if (recurType
== KARecurrence::MINUTELY
&& mAlarmTime
.isDateOnly())
590 setError(xi18nc("@info:shell", "Invalid <icode>%1</icode> parameter for date-only alarm", optionName(opt
)));
592 mReminderMinutes
= -mReminderMinutes
;
594 mFlags
|= KAEvent::REMINDER_ONCE
;
597 if (mParser
->isSet(*mOptions
[LATE_CANCEL
]))
599 KARecurrence::Type recurType
;
600 bool ok
= convInterval(mParser
->value(*mOptions
[LATE_CANCEL
]), recurType
, mLateCancel
);
602 setErrorParameter(LATE_CANCEL
);
604 else if (mParser
->isSet(*mOptions
[AUTO_CLOSE
]))
605 setErrorRequires(AUTO_CLOSE
, LATE_CANCEL
);
607 if (mParser
->isSet(*mOptions
[ACK_CONFIRM
]))
608 mFlags
|= KAEvent::CONFIRM_ACK
;
609 if (mParser
->isSet(*mOptions
[AUTO_CLOSE
]))
610 mFlags
|= KAEvent::AUTO_CLOSE
;
611 if (mParser
->isSet(*mOptions
[BEEP
]))
612 mFlags
|= KAEvent::BEEP
;
613 if (mParser
->isSet(*mOptions
[SPEAK
]))
614 mFlags
|= KAEvent::SPEAK
;
615 if (mParser
->isSet(*mOptions
[KORGANIZER
]))
616 mFlags
|= KAEvent::COPY_KORGANIZER
;
617 if (mParser
->isSet(*mOptions
[DISABLE
]))
618 mFlags
|= KAEvent::DISABLED
;
620 mFlags
|= KAEvent::REPEAT_SOUND
;
621 if (mParser
->isSet(*mOptions
[LOGIN
]))
622 mFlags
|= KAEvent::REPEAT_AT_LOGIN
;
623 if (mParser
->isSet(*mOptions
[BCC
]))
624 mFlags
|= KAEvent::EMAIL_BCC
;
625 if (mAlarmTime
.isDateOnly())
626 mFlags
|= KAEvent::ANY_TIME
;
631 // No arguments - run interactively & display the main window
632 if (!mError
.isEmpty())
634 qCDebug(KALARM_LOG
) << "Interactive";
636 if (mParser
->isSet(*mOptions
[ACK_CONFIRM
]))
637 errors
<< optionName(ACK_CONFIRM
);
638 if (mParser
->isSet(*mOptions
[ATTACH
]))
639 errors
<< optionName(ATTACH
);
640 if (mParser
->isSet(*mOptions
[AUTO_CLOSE
]))
641 errors
<< optionName(AUTO_CLOSE
);
642 if (mParser
->isSet(*mOptions
[BCC
]))
643 errors
<< optionName(BCC
);
644 if (mParser
->isSet(*mOptions
[BEEP
]))
645 errors
<< optionName(BEEP
);
646 if (mParser
->isSet(*mOptions
[COLOUR
]))
647 errors
<< optionName(COLOUR
);
648 if (mParser
->isSet(*mOptions
[COLOURFG
]))
649 errors
<< optionName(COLOURFG
);
650 if (mParser
->isSet(*mOptions
[DISABLE
]))
651 errors
<< optionName(DISABLE
);
652 if (mParser
->isSet(*mOptions
[FROM_ID
]))
653 errors
<< optionName(FROM_ID
);
654 if (mParser
->isSet(*mOptions
[KORGANIZER
]))
655 errors
<< optionName(KORGANIZER
);
656 if (mParser
->isSet(*mOptions
[LATE_CANCEL
]))
657 errors
<< optionName(LATE_CANCEL
);
658 if (mParser
->isSet(*mOptions
[LOGIN
]))
659 errors
<< optionName(LOGIN
);
660 if (mParser
->isSet(*mOptions
[PLAY
]))
661 errors
<< optionName(PLAY
);
662 if (mParser
->isSet(*mOptions
[PLAY_REPEAT
]))
663 errors
<< optionName(PLAY_REPEAT
);
664 if (mParser
->isSet(*mOptions
[REMINDER
]))
665 errors
<< optionName(REMINDER
);
666 if (mParser
->isSet(*mOptions
[REMINDER_ONCE
]))
667 errors
<< optionName(REMINDER_ONCE
);
668 if (mParser
->isSet(*mOptions
[SPEAK
]))
669 errors
<< optionName(SPEAK
);
670 if (mParser
->isSet(*mOptions
[SUBJECT
]))
671 errors
<< optionName(SUBJECT
);
672 if (mParser
->isSet(*mOptions
[TIME
]))
673 errors
<< optionName(TIME
);
674 if (mParser
->isSet(*mOptions
[VOLUME
]))
675 errors
<< optionName(VOLUME
);
676 if (!errors
.isEmpty())
677 mError
= errors
.join(QLatin1Char(' ')) + i18nc("@info:shell", ": option(s) only valid with an appropriate action option or message");
684 if (!mError
.isEmpty())
687 mCommand
= CMD_ERROR
;
691 void CommandOptions::printError(const QString
& errmsg
)
693 qCDebug(KALARM_LOG
)<<"ERROR=====================";
694 // Note: we can't use mArgs->usage() since that also quits any other
695 // running 'instances' of the program.
696 std::cerr
<< errmsg
.toLocal8Bit().data()
697 << i18nc("@info:shell", "\nUse --help to get a list of available command line options.\n").toLocal8Bit().data();
700 /******************************************************************************
701 * Check if the given command option is specified, and if so set mCommand etc.
702 * If another command option has also been detected, issue an error.
703 * If 'allowedEditType' is set, supersede any previous specification of that
704 * edit type with the given command option - this allows, e.g., --mail to be
705 * used along with --edit-new-email so the user can specify addressees.
707 bool CommandOptions::checkCommand(Option command
, Command code
, EditAlarmDlg::Type allowedEditType
)
709 if (!mError
.isEmpty()
710 || !mParser
->isSet(*mOptions
[command
]))
713 && (allowedEditType
== EditAlarmDlg::NO_TYPE
714 || (allowedEditType
!= EditAlarmDlg::NO_TYPE
&& (mCommand
!= NEW
|| mEditType
!= allowedEditType
))))
715 setErrorIncompatible(mCommandOpt
, command
);
716 qCDebug(KALARM_LOG
).nospace() << optionName(command
);
718 mCommandOpt
= command
;
722 // Set the error message to "--opt requires --opt2" or "--opt requires --opt2 or --opt3".
723 void CommandOptions::setErrorRequires(Option opt
, Option opt2
, Option opt3
)
725 if (opt3
== Num_Options
)
726 setError(xi18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode>", optionName(opt
), optionName(opt2
)));
728 setError(xi18nc("@info:shell", "<icode>%1</icode> requires <icode>%2</icode> or <icode>%3</icode>", optionName(opt
), optionName(opt2
), optionName(opt3
)));
731 void CommandOptions::setErrorParameter(Option opt
)
733 setError(xi18nc("@info:shell", "Invalid <icode>%1</icode> parameter", optionName(opt
)));
736 void CommandOptions::setErrorIncompatible(Option opt1
, Option opt2
)
738 setError(xi18nc("@info:shell", "<icode>%1</icode> incompatible with <icode>%2</icode>", optionName(opt1
), optionName(opt2
)));
741 void CommandOptions::checkEditType(EditAlarmDlg::Type type1
, EditAlarmDlg::Type type2
, Option opt
)
743 if (mParser
->isSet(*mOptions
[opt
]) && mCommand
!= NONE
744 && ((mCommand
!= NEW
&& mCommand
!= EDIT_NEW
) || (mEditType
!= type1
&& (type2
== EditAlarmDlg::NO_TYPE
|| mEditType
!= type2
))))
745 setErrorIncompatible(opt
, mCommandOpt
);
748 // Fetch one of the arguments (i.e. not belonging to any option).
749 QString
CommandOptions::arg(int n
)
751 const QStringList args
= mParser
->positionalArguments();
752 return (n
< args
.size()) ? args
[n
] : QString();
755 QString
CommandOptions::optionName(Option opt
, bool shortName
)
757 if (opt
== Opt_Message
)
758 return QStringLiteral("message");
759 const QStringList names
= mOptions
[opt
]->names();
762 for (int i
= 0; i
< names
.size(); ++i
)
764 if (shortName
&& names
[i
].size() == 1)
765 return QStringLiteral("-") + names
[i
];
766 else if (!shortName
&& names
[i
].size() > 1)
767 return QStringLiteral("--") + names
[i
];
769 return QStringLiteral("-") + names
[0];
775 /******************************************************************************
776 * Convert a non-zero positive time interval command line parameter.
777 * 'timeInterval' receives the count for the recurType. If 'allowMonthYear' is
778 * false, weeks and days are converted to minutes.
779 * Reply = true if successful.
781 bool convInterval(const QString
& timeParam
, KARecurrence::Type
& recurType
, int& timeInterval
, bool allowMonthYear
)
783 QByteArray timeString
= timeParam
.toLocal8Bit();
784 // Get the recurrence interval
787 uint length
= timeString
.length();
788 switch (timeString
[length
- 1])
793 recurType
= KARecurrence::ANNUAL_DATE
;
794 timeString
= timeString
.left(length
- 1);
797 recurType
= KARecurrence::WEEKLY
;
798 timeString
= timeString
.left(length
- 1);
801 recurType
= KARecurrence::DAILY
;
802 timeString
= timeString
.left(length
- 1);
806 int i
= timeString
.indexOf('H');
811 recurType
= KARecurrence::MONTHLY_DAY
;
812 timeString
= timeString
.left(length
- 1);
816 recurType
= KARecurrence::MINUTELY
;
817 interval
= timeString
.left(i
).toUInt(&ok
) * 60;
818 timeString
= timeString
.mid(i
+ 1, length
- i
- 2);
822 default: // should be a digit
823 recurType
= KARecurrence::MINUTELY
;
827 interval
+= timeString
.toUInt(&ok
);
830 // Convert time interval to minutes
833 case KARecurrence::WEEKLY
:
835 // fall through to DAILY
836 case KARecurrence::DAILY
:
838 recurType
= KARecurrence::MINUTELY
;
844 timeInterval
= static_cast<int>(interval
);
845 return ok
&& interval
;