File indexing completed on 2024-05-12 17:07:10
0001 /* 0002 SPDX-FileCopyrightText: 1998 Luca Montecchiani <m.luca@usa.net> 0003 SPDX-FileCopyrightText: 2015 David Edmundson <davidedmundson@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "main.h" 0009 0010 #include <time.h> 0011 #include <unistd.h> 0012 0013 #include <QVBoxLayout> 0014 0015 #include <KAboutData> 0016 #include <KMessageBox> 0017 #include <KPluginFactory> 0018 #include <QDBusConnection> 0019 0020 #include "dtime.h" 0021 #include "helper.h" 0022 0023 #include <kauth_version.h> 0024 #if KAUTH_VERSION >= QT_VERSION_CHECK(5, 92, 0) 0025 #include <KAuth/Action> 0026 #include <KAuth/ExecuteJob> 0027 #else 0028 #include <KAuthAction> 0029 #include <KAuthExecuteJob> 0030 #endif 0031 0032 #include "timedated_interface.h" 0033 0034 K_PLUGIN_CLASS_WITH_JSON(KclockModule, "kcm_clock.json") 0035 0036 KclockModule::KclockModule(QWidget *parent, const QVariantList &) 0037 : KCModule(parent) 0038 { 0039 auto reply = QDBusConnection::systemBus().call(QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"), 0040 QStringLiteral("/org/freedesktop/DBus"), 0041 QStringLiteral("org.freedesktop.DBus"), 0042 QStringLiteral("ListActivatableNames"))); 0043 0044 if (!reply.arguments().isEmpty() && reply.arguments().constFirst().value<QStringList>().contains(QLatin1String("org.freedesktop.timedate1"))) { 0045 m_haveTimedated = true; 0046 } 0047 0048 KAboutData *about = new KAboutData(QStringLiteral("kcmclock"), 0049 i18n("KDE Clock Control Module"), 0050 QStringLiteral("1.0"), 0051 QString(), 0052 KAboutLicense::GPL, 0053 i18n("(c) 1996 - 2001 Luca Montecchiani")); 0054 0055 about->addAuthor(i18n("Luca Montecchiani"), i18n("Original author"), QStringLiteral("m.luca@usa.net")); 0056 about->addAuthor(i18n("Paul Campbell"), i18n("Current Maintainer"), QStringLiteral("paul@taniwha.com")); 0057 about->addAuthor(i18n("Benjamin Meyer"), i18n("Added NTP support"), QStringLiteral("ben+kcmclock@meyerhome.net")); 0058 setAboutData(about); 0059 setQuickHelp( 0060 i18n("<h1>Date & Time</h1> This control module can be used to set the system date and" 0061 " time. As these settings do not only affect you as a user, but rather the whole system, you" 0062 " can only change these settings when you start the System Settings as root. If you do not have" 0063 " the root password, but feel the system time should be corrected, please contact your system" 0064 " administrator.")); 0065 0066 QVBoxLayout *layout = new QVBoxLayout(this); 0067 layout->setContentsMargins(0, 0, 0, 0); 0068 0069 dtime = new Dtime(this, m_haveTimedated); 0070 layout->addWidget(dtime); 0071 connect(dtime, SIGNAL(timeChanged(bool)), this, SIGNAL(changed(bool))); 0072 0073 setButtons(Help | Apply); 0074 0075 if (m_haveTimedated) { 0076 setAuthAction(KAuth::Action(QStringLiteral("org.freedesktop.timedate1.set-time"))); 0077 } else { 0078 // auth action name will be automatically guessed from the KCM name 0079 qWarning() << "Timedated not found, using legacy saving mode"; 0080 setNeedsAuthorization(true); 0081 } 0082 } 0083 0084 bool KclockModule::kauthSave() 0085 { 0086 QVariantMap helperargs; 0087 helperargs[QStringLiteral("ntp")] = true; 0088 helperargs[QStringLiteral("ntpServers")] = dtime->ntpServers(); 0089 helperargs[QStringLiteral("ntpEnabled")] = dtime->ntpEnabled(); 0090 0091 if (!dtime->ntpEnabled()) { 0092 QDateTime newTime = dtime->userTime(); 0093 qDebug() << "Set date to " << dtime->userTime(); 0094 helperargs[QStringLiteral("date")] = true; 0095 helperargs[QStringLiteral("newdate")] = QString::number(newTime.toTime_t()); 0096 helperargs[QStringLiteral("olddate")] = QString::number(::time(nullptr)); 0097 } 0098 0099 QString selectedTimeZone = dtime->selectedTimeZone(); 0100 if (!selectedTimeZone.isEmpty()) { 0101 helperargs[QStringLiteral("tz")] = true; 0102 helperargs[QStringLiteral("tzone")] = selectedTimeZone; 0103 } else { 0104 helperargs[QStringLiteral("tzreset")] = true; // make the helper reset the timezone 0105 } 0106 0107 Action action = authAction(); 0108 action.setArguments(helperargs); 0109 0110 ExecuteJob *job = action.execute(); 0111 bool rc = job->exec(); 0112 if (!rc) { 0113 KMessageBox::error(this, i18n("Unable to authenticate/execute the action: %1, %2", job->error(), job->errorString())); 0114 } 0115 return rc; 0116 } 0117 0118 bool KclockModule::timedatedSave() 0119 { 0120 OrgFreedesktopTimedate1Interface timedateIface(QStringLiteral("org.freedesktop.timedate1"), 0121 QStringLiteral("/org/freedesktop/timedate1"), 0122 QDBusConnection::systemBus()); 0123 0124 bool rc = true; 0125 // final arg in each method is "user-interaction" i.e whether it's OK for polkit to ask for auth 0126 0127 // we cannot send requests up front then block for all replies as we need NTP to be disabled before we can make a call to SetTime 0128 // timedated processes these in parallel and will return an error otherwise 0129 0130 auto reply = timedateIface.SetNTP(dtime->ntpEnabled(), true); 0131 reply.waitForFinished(); 0132 if (reply.isError()) { 0133 KMessageBox::error(this, i18n("Unable to change NTP settings")); 0134 qWarning() << "Failed to enable NTP" << reply.error().name() << reply.error().message(); 0135 rc = false; 0136 } 0137 0138 if (!dtime->ntpEnabled()) { 0139 qint64 timeDiff = dtime->userTime().toMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch(); 0140 //*1000 for milliseconds -> microseconds 0141 auto reply = timedateIface.SetTime(timeDiff * 1000, true, true); 0142 reply.waitForFinished(); 0143 if (reply.isError()) { 0144 KMessageBox::error(this, i18n("Unable to set current time")); 0145 qWarning() << "Failed to set current time" << reply.error().name() << reply.error().message(); 0146 rc = false; 0147 } 0148 } 0149 QString selectedTimeZone = dtime->selectedTimeZone(); 0150 if (!selectedTimeZone.isEmpty()) { 0151 auto reply = timedateIface.SetTimezone(selectedTimeZone, true); 0152 reply.waitForFinished(); 0153 if (reply.isError()) { 0154 KMessageBox::error(this, i18n("Unable to set timezone")); 0155 qWarning() << "Failed to set timezone" << reply.error().name() << reply.error().message(); 0156 rc = false; 0157 } 0158 } 0159 0160 return rc; 0161 } 0162 0163 void KclockModule::save() 0164 { 0165 setDisabled(true); 0166 0167 bool success = false; 0168 if (m_haveTimedated) { 0169 success = timedatedSave(); 0170 } else { 0171 success = kauthSave(); 0172 } 0173 0174 if (success) { 0175 QDBusMessage msg = QDBusMessage::createSignal(QStringLiteral("/org/kde/kcmshell_clock"), // 0176 QStringLiteral("org.kde.kcmshell_clock"), 0177 QStringLiteral("clockUpdated")); 0178 QDBusConnection::sessionBus().send(msg); 0179 } 0180 0181 // NOTE: super nasty hack #1 0182 // Try to work around time mismatch between KSystemTimeZones' update of local 0183 // timezone and reloading of data, so that the new timezone is taken into account. 0184 // The Ultimate solution to this would be if KSTZ emitted a signal when a new 0185 // local timezone was found. 0186 0187 // setDisabled(false) happens in load(), since QTimer::singleShot is non-blocking 0188 if (!m_haveTimedated) { 0189 QTimer::singleShot(5000, this, SLOT(load())); 0190 } else { 0191 load(); 0192 } 0193 } 0194 0195 void KclockModule::load() 0196 { 0197 dtime->load(); 0198 setDisabled(false); 0199 } 0200 0201 #include "main.moc"