File indexing completed on 2024-05-12 04:06:05
0001 /* 0002 This file is part of the KDE games library 0003 SPDX-FileCopyrightText: 2001 Andreas Beckermann <b_mann@gmx.de> 0004 SPDX-FileCopyrightText: 2003 Nicolas Hadacek <hadacek@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only 0007 */ 0008 0009 #include "kgamehighscore.h" 0010 0011 // own 0012 #include <config-highscore.h> 0013 #include <kdegames_highscore_logging.h> 0014 // KF 0015 #include <KConfig> 0016 #include <KConfigGroup> 0017 #include <KLocalizedString> 0018 #include <KMessageBox> 0019 #include <KSharedConfig> 0020 #include <KStandardGuiItem> 0021 // Qt 0022 #include <QFile> 0023 #include <QLockFile> 0024 0025 #ifndef WIN32 0026 #include <unistd.h> // sleep 0027 #else 0028 #include <qt_windows.h> 0029 #endif 0030 0031 #define GROUP "KHighscore" 0032 0033 class KGameHighscorePrivate 0034 { 0035 public: 0036 KGameHighscorePrivate() = default; 0037 0038 public: 0039 QString group; 0040 bool global; 0041 }; 0042 0043 class KGameHighscoreLockedConfig 0044 { 0045 public: 0046 ~KGameHighscoreLockedConfig(); 0047 QLockFile *lock; 0048 KConfig *config; 0049 }; 0050 0051 KGameHighscoreLockedConfig::~KGameHighscoreLockedConfig() 0052 { 0053 delete lock; 0054 delete config; 0055 } 0056 0057 Q_GLOBAL_STATIC(KGameHighscoreLockedConfig, lockedConfig) 0058 0059 KGameHighscore::KGameHighscore(bool forceLocal, QObject *parent) 0060 : QObject(parent) 0061 , d_ptr(new KGameHighscorePrivate) 0062 { 0063 init(forceLocal); 0064 } 0065 0066 void KGameHighscore::init(bool forceLocal) 0067 { 0068 Q_D(KGameHighscore); 0069 0070 #ifdef HIGHSCORE_DIRECTORY 0071 d->global = !forceLocal; 0072 if (d->global && lockedConfig->lock == 0) // If we're doing global highscores but not KFileLock has been set up yet 0073 { 0074 qCWarning(KDEGAMES_HIGHSCORE_LOG) << "KGameHighscore::init should be called before!!"; 0075 abort(); 0076 } 0077 #else 0078 d->global = false; 0079 Q_UNUSED(forceLocal); 0080 #endif 0081 readCurrentConfig(); 0082 } 0083 0084 bool KGameHighscore::isLocked() const 0085 { 0086 Q_D(const KGameHighscore); 0087 0088 return (d->global ? lockedConfig->lock->isLocked() : true); 0089 } 0090 0091 void KGameHighscore::readCurrentConfig() 0092 { 0093 Q_D(KGameHighscore); 0094 0095 if (d->global) 0096 lockedConfig->config->reparseConfiguration(); 0097 } 0098 0099 void KGameHighscore::init(const char *appname) 0100 { 0101 #ifdef HIGHSCORE_DIRECTORY 0102 const QString filename = QString::fromLocal8Bit("%1/%2.scores").arg(HIGHSCORE_DIRECTORY).arg(appname); 0103 0104 // int fd = fopen(filename.toLocal8Bit(), O_RDWR); 0105 /*QFile file(filename); 0106 if ( !file.open(QIODevice::ReadWrite) ) 0107 { 0108 qCWarning(KDEGAMES_HIGHSCORE_LOG) << "cannot open global highscore file \"" 0109 << filename << "\""; 0110 abort(); 0111 }*/ 0112 0113 /*if (!(QFile::permissions(filename) & QFile::WriteOwner)) 0114 { 0115 qCWarning(KDEGAMES_HIGHSCORE_LOG) << "cannot write to global highscore file \"" 0116 << filename << "\""; 0117 abort(); 0118 }*/ 0119 0120 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "Global highscore file \"" << filename << "\""; 0121 lockedConfig->lock = new QLockFile(filename); 0122 lockedConfig->config = new KConfig(filename, KConfig::NoGlobals); // read-only (matt-?) 0123 0124 // drop the effective gid 0125 #ifdef __GNUC__ 0126 #warning not portable yet. Unix only. Actually it does not even work there yet. 0127 #endif 0128 int gid = getgid(); 0129 setregid(gid, gid); 0130 #else 0131 Q_UNUSED(appname); 0132 #endif 0133 } 0134 0135 bool KGameHighscore::lockForWriting(QWidget *widget) 0136 { 0137 if (isLocked()) 0138 return true; 0139 0140 bool first = true; 0141 for (;;) { 0142 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "try locking"; 0143 // lock the highscore file (it should exist) 0144 int result = lockedConfig->lock->lock(); 0145 bool ok = (result == 0); 0146 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "locking system-wide highscore file res=" << result << " (ok=" << ok << ")"; 0147 if (ok) { 0148 readCurrentConfig(); 0149 return true; 0150 } 0151 0152 if (!first) { 0153 KGuiItem item = KStandardGuiItem::cont(); 0154 item.setText(i18n("Retry")); 0155 int res = KMessageBox::warningContinueCancel(widget, 0156 i18n("Cannot access the highscore file. Another user is probably currently writing to it."), 0157 QString(), 0158 item, 0159 KStandardGuiItem::cancel(), 0160 QStringLiteral("ask_lock_global_highscore_file")); 0161 if (res == KMessageBox::Cancel) 0162 break; 0163 } else { 0164 #ifdef WIN32 0165 Sleep(1000); 0166 #else 0167 sleep(1); 0168 #endif 0169 } 0170 first = false; 0171 } 0172 return false; 0173 } 0174 0175 void KGameHighscore::writeAndUnlock() 0176 { 0177 Q_D(KGameHighscore); 0178 0179 if (!d->global) { 0180 KSharedConfig::openConfig()->sync(); 0181 return; 0182 } 0183 if (!isLocked()) 0184 return; 0185 0186 qCDebug(KDEGAMES_HIGHSCORE_LOG) << "unlocking"; 0187 lockedConfig->config->sync(); // write config 0188 lockedConfig->lock->unlock(); 0189 } 0190 0191 KGameHighscore::~KGameHighscore() 0192 { 0193 writeAndUnlock(); 0194 } 0195 0196 KConfig *KGameHighscore::config() const 0197 { 0198 Q_D(const KGameHighscore); 0199 0200 return (d->global ? lockedConfig->config : static_cast<KConfig *>(KSharedConfig::openConfig().data())); 0201 } 0202 0203 void KGameHighscore::writeEntry(int entry, const QString &key, const QVariant &value) 0204 { 0205 Q_ASSERT(isLocked()); 0206 KConfigGroup cg(config(), group()); 0207 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key); 0208 cg.writeEntry(confKey, value); 0209 } 0210 0211 void KGameHighscore::writeEntry(int entry, const QString &key, int value) 0212 { 0213 Q_ASSERT(isLocked()); 0214 KConfigGroup cg(config(), group()); 0215 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key); 0216 cg.writeEntry(confKey, value); 0217 } 0218 0219 void KGameHighscore::writeEntry(int entry, const QString &key, const QString &value) 0220 { 0221 Q_ASSERT(isLocked()); 0222 KConfigGroup cg(config(), group()); 0223 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key); 0224 cg.writeEntry(confKey, value); 0225 } 0226 0227 QVariant KGameHighscore::readPropertyEntry(int entry, const QString &key, const QVariant &pDefault) const 0228 { 0229 KConfigGroup cg(config(), group()); 0230 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key); 0231 return cg.readEntry(confKey, pDefault); 0232 } 0233 0234 QString KGameHighscore::readEntry(int entry, const QString &key, const QString &pDefault) const 0235 { 0236 KConfigGroup cg(config(), group()); 0237 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key); 0238 return cg.readEntry(confKey, pDefault); 0239 } 0240 0241 int KGameHighscore::readNumEntry(int entry, const QString &key, int pDefault) const 0242 { 0243 KConfigGroup cg(config(), group()); 0244 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key); 0245 return cg.readEntry(confKey, pDefault); 0246 } 0247 0248 bool KGameHighscore::hasEntry(int entry, const QString &key) const 0249 { 0250 KConfigGroup cg(config(), group()); 0251 QString confKey = QStringLiteral("%1_%2").arg(entry).arg(key); 0252 return cg.hasKey(confKey); 0253 } 0254 0255 QStringList KGameHighscore::readList(const QString &key, int lastEntry) const 0256 { 0257 QStringList list; 0258 if (lastEntry > 0) { 0259 list.reserve(lastEntry); 0260 } 0261 for (int i = 1; hasEntry(i, key) && ((lastEntry > 0) ? (i <= lastEntry) : true); i++) { 0262 list.append(readEntry(i, key)); 0263 } 0264 return list; 0265 } 0266 0267 void KGameHighscore::writeList(const QString &key, const QStringList &list) 0268 { 0269 for (int i = 1; i <= list.count(); i++) { 0270 writeEntry(i, key, list[i - 1]); 0271 } 0272 } 0273 0274 void KGameHighscore::setHighscoreGroup(const QString &group) 0275 { 0276 Q_D(KGameHighscore); 0277 0278 d->group = group; 0279 } 0280 0281 QString KGameHighscore::highscoreGroup() const 0282 { 0283 Q_D(const KGameHighscore); 0284 0285 return d->group; 0286 } 0287 0288 QStringList KGameHighscore::groupList() const 0289 { 0290 const QStringList groupList = config()->groupList(); 0291 QStringList highscoreGroupList; 0292 for (QString group : groupList) { 0293 if (group.contains(QLatin1String("KHighscore"))) // If it's one of _our_ groups (KHighscore or KHighscore_xxx) 0294 { 0295 if (group == QLatin1String("KHighscore")) 0296 group.remove(QStringLiteral("KHighscore")); // Set to blank 0297 else 0298 group.remove(QStringLiteral("KHighscore_")); // Remove the KHighscore_ prefix 0299 highscoreGroupList << group; 0300 } 0301 } 0302 0303 return highscoreGroupList; 0304 } 0305 0306 QString KGameHighscore::group() const 0307 { 0308 Q_D(const KGameHighscore); 0309 0310 if (highscoreGroup().isEmpty()) 0311 return (d->global ? QString() : QStringLiteral(GROUP)); 0312 return (d->global ? highscoreGroup() : QStringLiteral("%1_%2").arg(QStringLiteral(GROUP), highscoreGroup())); 0313 } 0314 0315 bool KGameHighscore::hasTable() const 0316 { 0317 return config()->hasGroup(group()); 0318 } 0319 0320 #include "moc_kgamehighscore.cpp"