File indexing completed on 2024-04-28 05:35:31

0001 /*
0002     SPDX-FileCopyrightText: 2005-2010 David Jarvie <djarvie@kde.org>
0003     SPDX-FileCopyrightText: 2005 S.R.Haque <srhaque@iee.org>
0004     SPDX-FileCopyrightText: 2013 Martin Klapetek <mklapetek@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "ktimezoned.h"
0010 
0011 #include <QDBusConnection>
0012 #include <QDBusMessage>
0013 #include <QDebug>
0014 #include <QDir>
0015 #include <QFileInfo>
0016 #include <QTimeZone>
0017 
0018 #include <KConfig>
0019 #include <KConfigGroup>
0020 #include <KDirWatch>
0021 #include <KPluginFactory>
0022 
0023 using namespace Qt::StringLiterals;
0024 
0025 K_PLUGIN_CLASS_WITH_JSON(KTimeZoned, "ktimezoned.json")
0026 
0027 const char LOCAL_ZONE[] = "LocalZone"; // name of local time zone
0028 const char ZONEINFO_DIR[] = "ZoneinfoDir"; // path to zoneinfo/ directory
0029 const char ZONE_TAB[] = "Zonetab"; // path & name of zone.tab
0030 
0031 KTimeZoned::KTimeZoned(QObject *parent, const QList<QVariant> &l)
0032     : KTimeZonedBase(parent, l)
0033 {
0034     init(false);
0035 }
0036 
0037 KTimeZoned::~KTimeZoned()
0038 {
0039     delete m_dirWatch;
0040     m_dirWatch = nullptr;
0041     delete m_zoneTabWatch;
0042     m_zoneTabWatch = nullptr;
0043 }
0044 
0045 void KTimeZoned::init(bool restart)
0046 {
0047     if (restart) {
0048         delete m_dirWatch;
0049         m_dirWatch = nullptr;
0050         delete m_zoneTabWatch;
0051         m_zoneTabWatch = nullptr;
0052         m_localZone = QString();
0053         m_zoneinfoDir = QString();
0054         m_zoneTab = QString();
0055     }
0056 
0057     KConfig config(QStringLiteral("ktimezonedrc"));
0058     if (restart)
0059         config.reparseConfiguration();
0060 
0061     KConfigGroup group(&config, u"TimeZones"_s);
0062     m_localZone = group.readEntry(LOCAL_ZONE);
0063     m_zoneinfoDir = group.readEntry(ZONEINFO_DIR);
0064     m_zoneTab = group.readEntry(ZONE_TAB);
0065 
0066     updateLocalZone();
0067 
0068     if (!m_dirWatch) {
0069         m_dirWatch = new KDirWatch(this);
0070         m_dirWatch->addFile(QStringLiteral("/etc/timezone"));
0071         m_dirWatch->addFile(QStringLiteral("/etc/localtime"));
0072 
0073         connect(m_dirWatch, &KDirWatch::dirty, this, &KTimeZoned::updateLocalZone);
0074         connect(m_dirWatch, &KDirWatch::deleted, this, &KTimeZoned::updateLocalZone);
0075         connect(m_dirWatch, &KDirWatch::created, this, &KTimeZoned::updateLocalZone);
0076     }
0077 
0078     if (!m_zoneTabWatch && findZoneTab(m_zoneTab)) {
0079         // cache the values so we don't look it up on next startup
0080         KConfig config(QStringLiteral("ktimezonedrc"));
0081         KConfigGroup group(&config, u"TimeZones"_s);
0082         group.writeEntry(ZONEINFO_DIR, m_zoneinfoDir);
0083         group.writeEntry(ZONE_TAB, m_zoneTab);
0084         group.sync();
0085 
0086         m_zoneTabWatch = new KDirWatch(this);
0087         m_zoneTabWatch->addDir(m_zoneinfoDir, KDirWatch::WatchFiles);
0088 
0089         connect(m_dirWatch, &KDirWatch::dirty, this, &KTimeZoned::updateLocalZone);
0090         connect(m_dirWatch, &KDirWatch::created, this, &KTimeZoned::updateLocalZone);
0091         connect(m_dirWatch, &KDirWatch::deleted, this, &KTimeZoned::updateLocalZone);
0092     }
0093 }
0094 
0095 // Check if the local zone has been updated, and if so, write the new
0096 // zone to the config file and notify interested parties.
0097 void KTimeZoned::updateLocalZone()
0098 {
0099     QString systemTimeZone = QTimeZone::systemTimeZoneId();
0100 
0101     if (m_localZone != systemTimeZone) {
0102         qDebug() << "System timezone has been changed, new timezone is" << systemTimeZone;
0103 
0104         KConfig config(QStringLiteral("ktimezonedrc"));
0105         KConfigGroup group(&config, u"TimeZones"_s);
0106         m_localZone = systemTimeZone;
0107         group.writeEntry(LOCAL_ZONE, m_localZone);
0108         group.sync();
0109 
0110         QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Daemon"), QStringLiteral("org.kde.KTimeZoned"), QStringLiteral("timeZoneChanged"));
0111         QDBusConnection::sessionBus().send(message);
0112     }
0113 }
0114 
0115 /*
0116  * Find the location of the zoneinfo files and store in m_zoneinfoDir.
0117  */
0118 bool KTimeZoned::findZoneTab(const QString &pathFromConfig)
0119 {
0120     // First try the cached path
0121     if (QFileInfo::exists(pathFromConfig)) {
0122         return true;
0123     }
0124 
0125     const QString ZONE_TAB_FILE = QStringLiteral("/zone.tab");
0126     const QString ZONE_INFO_DIR = QStringLiteral("/usr/share/zoneinfo");
0127 
0128     // Find and open zone.tab - it's all easy except knowing where to look.
0129     // Try the LSB location first.
0130     QDir dir;
0131     QString zoneinfoDir = ZONE_INFO_DIR;
0132     QString zoneTab = ZONE_INFO_DIR + ZONE_TAB_FILE;
0133     // make a note if the dir exists; whether it contains zone.tab or not
0134     if (dir.exists(zoneinfoDir) && QFileInfo::exists(zoneTab)) {
0135         m_zoneinfoDir = zoneinfoDir;
0136         m_zoneTab = zoneTab;
0137         return true;
0138     }
0139 
0140     zoneinfoDir = QStringLiteral("/usr/lib/zoneinfo");
0141     zoneTab = zoneinfoDir + ZONE_TAB_FILE;
0142     if (dir.exists(zoneinfoDir) && QFileInfo::exists(zoneTab)) {
0143         m_zoneinfoDir = zoneinfoDir;
0144         m_zoneTab = zoneTab;
0145         return true;
0146     }
0147 
0148     zoneinfoDir = ::getenv("TZDIR");
0149     zoneTab = zoneinfoDir + ZONE_TAB_FILE;
0150     if (!zoneinfoDir.isEmpty() && dir.exists(zoneinfoDir) && QFileInfo::exists(zoneTab)) {
0151         m_zoneinfoDir = zoneinfoDir;
0152         m_zoneTab = zoneTab;
0153         return true;
0154     }
0155 
0156     zoneinfoDir = QLatin1String("/usr/share/lib/zoneinfo");
0157     zoneTab = zoneinfoDir + ZONE_TAB_FILE;
0158     if (dir.exists(zoneinfoDir + QLatin1String("/src")) && QFileInfo::exists(zoneTab)) {
0159         m_zoneinfoDir = zoneinfoDir;
0160         m_zoneTab = zoneTab;
0161         return true;
0162     }
0163 
0164     return false;
0165 }
0166 
0167 void KTimeZoned::zonetabChanged()
0168 {
0169     QDBusMessage message =
0170         QDBusMessage::createSignal(QStringLiteral("/Daemon"), QStringLiteral("org.kde.KTimeZoned"), QStringLiteral("timeZoneDatabaseUpdated"));
0171     QDBusConnection::sessionBus().send(message);
0172 }
0173 
0174 #include "ktimezoned.moc"
0175 #include "moc_ktimezonedbase.cpp"