• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kalarm

dbushandler.cpp

Go to the documentation of this file.
00001 /*
00002  *  dbushandler.cpp  -  handler for D-Bus calls by other applications
00003  *  Program:  kalarm
00004  *  Copyright © 2002-2008 by David Jarvie <djarvie@kde.org>
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 along
00017  *  with this program; if not, write to the Free Software Foundation, Inc.,
00018  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "kalarm.h"
00022 
00023 #include <stdlib.h>
00024 
00025 #include <QtDBus/QtDBus>
00026 #include <kdebug.h>
00027 #include <kcal/duration.h>
00028 
00029 #include "alarmcalendar.h"
00030 #include "functions.h"
00031 #include "kalarmapp.h"
00032 #include "kamail.h"
00033 #include "karecurrence.h"
00034 #include "mainwindow.h"
00035 #include "preferences.h"
00036 #include "dbushandler.moc"
00037 #include <kalarmadaptor.h>
00038 static const char* REQUEST_DBUS_OBJECT = "/kalarm";   // D-Bus object path of KAlarm's request interface
00039 
00040 
00041 /*=============================================================================
00042 = DBusHandler
00043 = This class's function is to handle D-Bus requests by other applications.
00044 =============================================================================*/
00045 DBusHandler::DBusHandler()
00046 {
00047     kDebug();
00048     new KalarmAdaptor(this);
00049     QDBusConnection::sessionBus().registerObject(REQUEST_DBUS_OBJECT, this);
00050 }
00051 
00052 
00053 bool DBusHandler::cancelEvent(const QString& eventId)
00054 {
00055     return theApp()->dbusDeleteEvent(eventId);
00056 }
00057 
00058 bool DBusHandler::triggerEvent(const QString& eventId)
00059 {
00060     return theApp()->dbusTriggerEvent(eventId);
00061 }
00062 
00063 bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
00064                                   const QString& bgColor, const QString& fgColor, const QString& font,
00065                                   const QString& audioUrl, int reminderMins, const QString& recurrence,
00066                                   int subRepeatInterval, int subRepeatCount)
00067 {
00068     KDateTime start;
00069     KARecurrence recur;
00070     KCal::Duration subRepeatDuration;
00071     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
00072         return false;
00073     return scheduleMessage(message, start, lateCancel, flags, bgColor, fgColor, font, KUrl(audioUrl), reminderMins, recur, subRepeatDuration, subRepeatCount);
00074 }
00075 
00076 bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
00077                                   const QString& bgColor, const QString& fgColor, const QString& font,
00078                                   const QString& audioUrl, int reminderMins,
00079                                   int recurType, int recurInterval, int recurCount)
00080 {
00081     KDateTime start;
00082     KARecurrence recur;
00083     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
00084         return false;
00085     return scheduleMessage(message, start, lateCancel, flags, bgColor, fgColor, font, KUrl(audioUrl), reminderMins, recur);
00086 }
00087 
00088 bool DBusHandler::scheduleMessage(const QString& message, const QString& startDateTime, int lateCancel, unsigned flags,
00089                                   const QString& bgColor, const QString& fgColor, const QString& font,
00090                                   const QString& audioUrl, int reminderMins,
00091                                   int recurType, int recurInterval, const QString& endDateTime)
00092 {
00093     KDateTime start;
00094     KARecurrence recur;
00095     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
00096         return false;
00097     return scheduleMessage(message, start, lateCancel, flags, bgColor, fgColor, font, KUrl(audioUrl), reminderMins, recur);
00098 }
00099 
00100 bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
00101                                const QString& audioUrl, int reminderMins, const QString& recurrence,
00102                                int subRepeatInterval, int subRepeatCount)
00103 {
00104     KDateTime start;
00105     KARecurrence recur;
00106     KCal::Duration subRepeatDuration;
00107     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
00108         return false;
00109     return scheduleFile(KUrl(url), start, lateCancel, flags, bgColor, KUrl(audioUrl), reminderMins, recur, subRepeatDuration, subRepeatCount);
00110 }
00111 
00112 bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
00113                                const QString& audioUrl, int reminderMins, int recurType, int recurInterval, int recurCount)
00114 {
00115     KDateTime start;
00116     KARecurrence recur;
00117     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
00118         return false;
00119     return scheduleFile(KUrl(url), start, lateCancel, flags, bgColor, KUrl(audioUrl), reminderMins, recur);
00120 }
00121 
00122 bool DBusHandler::scheduleFile(const QString& url, const QString& startDateTime, int lateCancel, unsigned flags, const QString& bgColor,
00123                                const QString& audioUrl, int reminderMins, int recurType, int recurInterval, const QString& endDateTime)
00124 {
00125     KDateTime start;
00126     KARecurrence recur;
00127     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
00128         return false;
00129     return scheduleFile(KUrl(url), start, lateCancel, flags, bgColor, KUrl(audioUrl), reminderMins, recur);
00130 }
00131 
00132 bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
00133                                   const QString& recurrence, int subRepeatInterval, int subRepeatCount)
00134 {
00135     KDateTime start;
00136     KARecurrence recur;
00137     KCal::Duration subRepeatDuration;
00138     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
00139         return false;
00140     return scheduleCommand(commandLine, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
00141 }
00142 
00143 bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
00144                                   int recurType, int recurInterval, int recurCount)
00145 {
00146     KDateTime start = convertDateTime(startDateTime);
00147     if (!start.isValid())
00148         return false;
00149     KARecurrence recur;
00150     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
00151         return false;
00152     return scheduleCommand(commandLine, start, lateCancel, flags, recur);
00153 }
00154 
00155 bool DBusHandler::scheduleCommand(const QString& commandLine, const QString& startDateTime, int lateCancel, unsigned flags,
00156                                   int recurType, int recurInterval, const QString& endDateTime)
00157 {
00158     KDateTime start;
00159     KARecurrence recur;
00160     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
00161         return false;
00162     return scheduleCommand(commandLine, start, lateCancel, flags, recur);
00163 }
00164 
00165 bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
00166                                 const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
00167                                 const QString& recurrence, int subRepeatInterval, int subRepeatCount)
00168 {
00169     KDateTime start;
00170     KARecurrence recur;
00171     KCal::Duration subRepeatDuration;
00172     if (!convertRecurrence(start, recur, startDateTime, recurrence, subRepeatInterval, subRepeatDuration))
00173         return false;
00174     return scheduleEmail(fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur, subRepeatDuration, subRepeatCount);
00175 }
00176 
00177 bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
00178                                 const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
00179                                 int recurType, int recurInterval, int recurCount)
00180 {
00181     KDateTime start;
00182     KARecurrence recur;
00183     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, recurCount))
00184         return false;
00185     return scheduleEmail(fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur);
00186 }
00187 
00188 bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject, const QString& message,
00189                                 const QString& attachments, const QString& startDateTime, int lateCancel, unsigned flags,
00190                                 int recurType, int recurInterval, const QString& endDateTime)
00191 {
00192     KDateTime start;
00193     KARecurrence recur;
00194     if (!convertRecurrence(start, recur, startDateTime, recurType, recurInterval, endDateTime))
00195         return false;
00196     return scheduleEmail(fromID, addresses, subject, message, attachments, start, lateCancel, flags, recur);
00197 }
00198 
00199 bool DBusHandler::edit(const QString& eventID)
00200 {
00201     return KAlarm::editAlarm(eventID);
00202 }
00203 
00204 bool DBusHandler::editNew(int type)
00205 {
00206     EditAlarmDlg::Type dlgtype;
00207     switch (type)
00208     {
00209         case DISPLAY:  dlgtype = EditAlarmDlg::DISPLAY;  break;
00210         case COMMAND:  dlgtype = EditAlarmDlg::COMMAND;  break;
00211         case EMAIL:    dlgtype = EditAlarmDlg::EMAIL;  break;
00212         default:
00213             kError() << "D-Bus call: invalid alarm type:" << type;
00214             return false;
00215     }
00216     KAlarm::editNewAlarm(dlgtype);
00217     return true;
00218 }
00219 
00220 bool DBusHandler::editNew(const QString& templateName)
00221 {
00222     return KAlarm::editNewAlarm(templateName);
00223 }
00224 
00225 
00226 /******************************************************************************
00227 * Schedule a message alarm, after converting the parameters from strings.
00228 */
00229 bool DBusHandler::scheduleMessage(const QString& message, const KDateTime& start, int lateCancel, unsigned flags,
00230                                   const QString& bgColor, const QString& fgColor, const QString& fontStr,
00231                                   const KUrl& audioFile, int reminderMins, const KARecurrence& recurrence,
00232                                   const KCal::Duration& subRepeatDuration, int subRepeatCount)
00233 {
00234     unsigned kaEventFlags = convertStartFlags(start, flags);
00235     KAEvent::Action action = (kaEventFlags & KAEvent::DISPLAY_COMMAND) ? KAEvent::COMMAND : KAEvent::MESSAGE;
00236     QColor bg = convertBgColour(bgColor);
00237     if (!bg.isValid())
00238         return false;
00239     QColor fg;
00240     if (fgColor.isEmpty())
00241         fg = Preferences::defaultFgColour();
00242     else
00243     {
00244         fg.setNamedColor(fgColor);
00245         if (!fg.isValid())
00246         {
00247             kError() << "D-Bus call: invalid foreground color:" << fgColor;
00248             return false;
00249         }
00250     }
00251     QFont font;
00252     if (fontStr.isEmpty())
00253         kaEventFlags |= KAEvent::DEFAULT_FONT;
00254     else
00255     {
00256         if (!font.fromString(fontStr))    // N.B. this doesn't do good validation
00257         {
00258             kError() << "D-Bus call: invalid font:" << fontStr;
00259             return false;
00260         }
00261     }
00262     return theApp()->scheduleEvent(action, message, start, lateCancel, kaEventFlags, bg, fg, font,
00263                                    audioFile.url(), -1, reminderMins, recurrence, subRepeatDuration, subRepeatCount);
00264 }
00265 
00266 /******************************************************************************
00267 * Schedule a file alarm, after converting the parameters from strings.
00268 */
00269 bool DBusHandler::scheduleFile(const KUrl& file,
00270                                const KDateTime& start, int lateCancel, unsigned flags, const QString& bgColor,
00271                                const KUrl& audioFile, int reminderMins, const KARecurrence& recurrence,
00272                                const KCal::Duration& subRepeatDuration, int subRepeatCount)
00273 {
00274     unsigned kaEventFlags = convertStartFlags(start, flags);
00275     QColor bg = convertBgColour(bgColor);
00276     if (!bg.isValid())
00277         return false;
00278     return theApp()->scheduleEvent(KAEvent::FILE, file.url(), start, lateCancel, kaEventFlags, bg, Qt::black, QFont(),
00279                                    audioFile.url(), -1, reminderMins, recurrence, subRepeatDuration, subRepeatCount);
00280 }
00281 
00282 /******************************************************************************
00283 * Schedule a command alarm, after converting the parameters from strings.
00284 */
00285 bool DBusHandler::scheduleCommand(const QString& commandLine,
00286                                   const KDateTime& start, int lateCancel, unsigned flags,
00287                                   const KARecurrence& recurrence, const KCal::Duration& subRepeatDuration, int subRepeatCount)
00288 {
00289     unsigned kaEventFlags = convertStartFlags(start, flags);
00290     return theApp()->scheduleEvent(KAEvent::COMMAND, commandLine, start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
00291                                    QString(), -1, 0, recurrence, subRepeatDuration, subRepeatCount);
00292 }
00293 
00294 /******************************************************************************
00295 * Schedule an email alarm, after validating the addresses and attachments.
00296 */
00297 bool DBusHandler::scheduleEmail(const QString& fromID, const QString& addresses, const QString& subject,
00298                                 const QString& message, const QString& attachments,
00299                                 const KDateTime& start, int lateCancel, unsigned flags,
00300                                 const KARecurrence& recurrence, const KCal::Duration& subRepeatDuration, int subRepeatCount)
00301 {
00302     unsigned kaEventFlags = convertStartFlags(start, flags);
00303     uint senderId = 0;
00304     if (!fromID.isEmpty())
00305     {
00306         senderId = KAMail::identityUoid(fromID);
00307         if (!senderId)
00308         {
00309             kError() << "D-Bus call scheduleEmail(): unknown sender ID:" << fromID;
00310             return false;
00311         }
00312     }
00313     EmailAddressList addrs;
00314     QString bad = KAMail::convertAddresses(addresses, addrs);
00315     if (!bad.isEmpty())
00316     {
00317         kError() << "D-Bus call scheduleEmail(): invalid email addresses:" << bad;
00318         return false;
00319     }
00320     if (addrs.isEmpty())
00321     {
00322         kError() << "D-Bus call scheduleEmail(): no email address";
00323         return false;
00324     }
00325     QStringList atts;
00326     bad = KAMail::convertAttachments(attachments, atts);
00327     if (!bad.isEmpty())
00328     {
00329         kError() << "D-Bus call scheduleEmail(): invalid email attachment:" << bad;
00330         return false;
00331     }
00332     return theApp()->scheduleEvent(KAEvent::EMAIL, message, start, lateCancel, kaEventFlags, Qt::black, Qt::black, QFont(),
00333                                    QString(), -1, 0, recurrence, subRepeatDuration, subRepeatCount, senderId, addrs, subject, atts);
00334 }
00335 
00336 
00337 /******************************************************************************
00338 * Convert the start date/time string to a KDateTime. The date/time string is in
00339 * the format YYYY-MM-DD[THH:MM[:SS]][ TZ] or [T]HH:MM[:SS].
00340 * The time zone specifier (TZ) is a system time zone name, e.g. "Europe/London".
00341 * If no time zone is specified, it defaults to the local clock time (which is
00342 * not the same as the local time zone).
00343 */
00344 KDateTime DBusHandler::convertDateTime(const QString& dateTime, const KDateTime& defaultDt)
00345 {
00346     int i = dateTime.indexOf(QChar(' '));
00347     QString dtString = dateTime.left(i);
00348     QString zone = dateTime.mid(i);
00349     QDate date;
00350     QTime time;
00351     bool haveTime = true;
00352     bool error = false;
00353     if (dtString.length() > 10)
00354     {
00355         // Both a date and a time are specified
00356         QDateTime dt = QDateTime::fromString(dtString, Qt::ISODate);
00357         error = !dt.isValid();
00358         date = dt.date();
00359         time = dt.time();
00360     }
00361     else
00362     {
00363         // Check whether a time is specified
00364         QString t;
00365         if (dtString[0] == QChar('T'))
00366             t = dtString.mid(1);     // it's a time: remove the leading 'T'
00367         else if (!dtString[2].isDigit())
00368             t = dtString;            // it's a time with no leading 'T'
00369 
00370         if (t.isEmpty())
00371         {
00372             // It's a date only
00373             date = QDate::fromString(dtString, Qt::ISODate);
00374             error = !date.isValid();
00375             haveTime = false;
00376         }
00377         else
00378         {
00379             // It's a time only
00380             time = QTime::fromString(t, Qt::ISODate);
00381             error = !time.isValid();
00382         }
00383     }
00384     KDateTime result;
00385     if (!error)
00386         result = KAlarm::applyTimeZone(zone, date, time, haveTime, defaultDt);
00387     if (error  ||  !result.isValid())
00388     {
00389         if (!defaultDt.isValid())
00390             kError() << "D-Bus call: invalid start date/time: '" << dateTime << "'";
00391         else
00392             kError() << "D-Bus call: invalid recurrence end date/time: '" << dateTime << "'";
00393     }
00394     return result;
00395 }
00396 
00397 /******************************************************************************
00398 * Convert the flag bits to KAEvent flag bits.
00399 */
00400 unsigned DBusHandler::convertStartFlags(const KDateTime& start, unsigned flags)
00401 {
00402     unsigned kaEventFlags = 0;
00403     if (flags & REPEAT_AT_LOGIN) kaEventFlags |= KAEvent::REPEAT_AT_LOGIN;
00404     if (flags & BEEP)            kaEventFlags |= KAEvent::BEEP;
00405     if (flags & SPEAK)           kaEventFlags |= KAEvent::SPEAK;
00406     if (flags & CONFIRM_ACK)     kaEventFlags |= KAEvent::CONFIRM_ACK;
00407     if (flags & REPEAT_SOUND)    kaEventFlags |= KAEvent::REPEAT_SOUND;
00408     if (flags & AUTO_CLOSE)      kaEventFlags |= KAEvent::AUTO_CLOSE;
00409     if (flags & EMAIL_BCC)       kaEventFlags |= KAEvent::EMAIL_BCC;
00410     if (flags & DISPLAY_COMMAND) kaEventFlags |= KAEvent::DISPLAY_COMMAND;
00411     if (flags & SCRIPT)          kaEventFlags |= KAEvent::SCRIPT;
00412     if (flags & EXEC_IN_XTERM)   kaEventFlags |= KAEvent::EXEC_IN_XTERM;
00413     if (flags & SHOW_IN_KORG)    kaEventFlags |= KAEvent::COPY_KORGANIZER;
00414     if (flags & DISABLED)        kaEventFlags |= KAEvent::DISABLED;
00415     if (start.isDateOnly())      kaEventFlags |= KAEvent::ANY_TIME;
00416     return kaEventFlags;
00417 }
00418 
00419 /******************************************************************************
00420 * Convert the background colour string to a QColor.
00421 */
00422 QColor DBusHandler::convertBgColour(const QString& bgColor)
00423 {
00424     if (bgColor.isEmpty())
00425         return Preferences::defaultBgColour();
00426     QColor bg(bgColor);
00427     if (!bg.isValid())
00428             kError() << "D-Bus call: invalid background color:" << bgColor;
00429     return bg;
00430 }
00431 
00432 bool DBusHandler::convertRecurrence(KDateTime& start, KARecurrence& recurrence, 
00433                                     const QString& startDateTime, const QString& icalRecurrence,
00434                     int subRepeatInterval, KCal::Duration& subRepeatDuration)
00435 {
00436     start = convertDateTime(startDateTime);
00437     if (!start.isValid())
00438         return false;
00439     if (!recurrence.set(icalRecurrence))
00440         return false;
00441     if (subRepeatInterval  &&  recurrence.type() == KARecurrence::NO_RECUR)
00442     {
00443         subRepeatInterval = 0;
00444         kWarning() << "D-Bus call: no recurrence specified, so sub-repetition ignored";
00445     }
00446     if (subRepeatInterval  &&  !(subRepeatInterval % (24*60)))
00447         subRepeatDuration = KCal::Duration(subRepeatInterval / (24*60), KCal::Duration::Days);
00448     else
00449         subRepeatDuration = KCal::Duration(subRepeatInterval * 60, KCal::Duration::Seconds);
00450     return true;
00451 }
00452 
00453 bool DBusHandler::convertRecurrence(KDateTime& start, KARecurrence& recurrence, const QString& startDateTime,
00454                                     int recurType, int recurInterval, int recurCount)
00455 {
00456     start = convertDateTime(startDateTime);
00457     if (!start.isValid())
00458         return false;
00459     return convertRecurrence(recurrence, start, recurType, recurInterval, recurCount, KDateTime());
00460 }
00461 
00462 bool DBusHandler::convertRecurrence(KDateTime& start, KARecurrence& recurrence, const QString& startDateTime,
00463                                     int recurType, int recurInterval, const QString& endDateTime)
00464 {
00465     start = convertDateTime(startDateTime);
00466     if (!start.isValid())
00467         return false;
00468     KDateTime end = convertDateTime(endDateTime, start);
00469     if (end.isDateOnly()  &&  !start.isDateOnly())
00470     {
00471         kError() << "D-Bus call: alarm is date-only, but recurrence end is date/time";
00472         return false;
00473     }
00474     if (!end.isDateOnly()  &&  start.isDateOnly())
00475     {
00476         kError() << "D-Bus call: alarm is timed, but recurrence end is date-only";
00477         return false;
00478     }
00479     return convertRecurrence(recurrence, start, recurType, recurInterval, 0, end);
00480 }
00481 
00482 bool DBusHandler::convertRecurrence(KARecurrence& recurrence, const KDateTime& start, int recurType,
00483                                     int recurInterval, int recurCount, const KDateTime& end)
00484 {
00485     KARecurrence::Type type;
00486     switch (recurType)
00487     {
00488         case MINUTELY:  type = KARecurrence::MINUTELY;  break;
00489         case DAILY:     type = KARecurrence::DAILY;  break;
00490         case WEEKLY:    type = KARecurrence::WEEKLY;  break;
00491         case MONTHLY:   type = KARecurrence::MONTHLY_DAY;  break;
00492         case YEARLY:    type = KARecurrence::ANNUAL_DATE;  break;
00493         default:
00494             kError() << "D-Bus call: invalid recurrence type:" << recurType;
00495             return false;
00496     }
00497     recurrence.set(type, recurInterval, recurCount, start, end);
00498     return true;
00499 }

kalarm

Skip menu "kalarm"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal