File indexing completed on 2024-04-28 16:54:29

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