File indexing completed on 2024-05-12 04:52:15
0001 /* 0002 * dvbmanager.cpp 0003 * 0004 * Copyright (C) 2008-2011 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #include "../log.h" 0022 0023 #include <config-kaffeine.h> 0024 #include <KConfigGroup> 0025 #include <KSharedConfig> 0026 #include <QDir> 0027 #include <QPluginLoader> 0028 #include <QRegularExpressionMatch> 0029 #include <QStandardPaths> 0030 0031 #include "dvbconfig.h" 0032 #include "dvbdevice.h" 0033 #include "dvbdevice_linux.h" 0034 #include "dvbepg.h" 0035 #include "dvbliveview.h" 0036 #include "dvbmanager.h" 0037 #include "dvbmanager_p.h" 0038 #include "dvbsi.h" 0039 #include "xmltv.h" 0040 0041 DvbManager::DvbManager(MediaWidget *mediaWidget_, QWidget *parent_) : QObject(parent_), 0042 parent(parent_), mediaWidget(mediaWidget_), channelView(NULL), dvbDumpEnabled(false) 0043 { 0044 channelModel = DvbChannelModel::createSqlModel(this); 0045 recordingModel = new DvbRecordingModel(this, this); 0046 epgModel = new DvbEpgModel(this, this); 0047 liveView = new DvbLiveView(this, this); 0048 xmlTv = new XmlTv(this); 0049 0050 readDeviceConfigs(); 0051 updateSourceMapping(); 0052 0053 loadDeviceManager(); 0054 0055 DvbSiText::setOverride6937(override6937Charset()); 0056 0057 QString xmlFile = getXmltvFileName(); 0058 0059 if (!xmlFile.isEmpty()) 0060 xmlTv->addFile(xmlFile); 0061 } 0062 0063 DvbManager::~DvbManager() 0064 { 0065 writeDeviceConfigs(); 0066 0067 // we need an explicit deletion order (device users ; devices ; device manager) 0068 0069 delete xmlTv; 0070 delete epgModel; 0071 epgModel = NULL; 0072 delete recordingModel; 0073 0074 foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) { 0075 delete deviceConfig.device; 0076 } 0077 } 0078 0079 DvbDevice *DvbManager::requestDevice(const QString &source, const DvbTransponder &transponder, 0080 DvbManager::RequestType requestType) 0081 { 0082 Q_ASSERT(requestType != Exclusive); 0083 // FIXME call DvbEpgModel::startEventFilter / DvbEpgModel::stopEventFilter here? 0084 0085 reacquireDevice = false; 0086 for (int i = 0; i < deviceConfigs.size(); ++i) { 0087 const DvbDeviceConfig &it = deviceConfigs.at(i); 0088 0089 if ((it.device == NULL) || (it.useCount < 1)) { 0090 continue; 0091 } 0092 0093 if ((it.source == source) && it.transponder.corresponds(transponder)) { 0094 ++deviceConfigs[i].useCount; 0095 0096 if (requestType == Prioritized) { 0097 ++deviceConfigs[i].prioritizedUseCount; 0098 } 0099 0100 return it.device; 0101 } 0102 } 0103 0104 for (int i = 0; i < deviceConfigs.size(); ++i) { 0105 const DvbDeviceConfig &it = deviceConfigs.at(i); 0106 0107 if ((it.device == NULL) || (it.useCount != 0)) { 0108 continue; 0109 } 0110 0111 foreach (const DvbConfig &config, it.configs) { 0112 if (config->name == source) { 0113 DvbDevice *device = it.device; 0114 0115 if (!device->acquire(config.constData())) { 0116 continue; 0117 } 0118 0119 deviceConfigs[i].useCount = 1; 0120 0121 if (requestType == Prioritized) { 0122 deviceConfigs[i].prioritizedUseCount = 1; 0123 } 0124 0125 deviceConfigs[i].source = source; 0126 deviceConfigs[i].transponder = transponder; 0127 device->tune(transponder); 0128 return device; 0129 } 0130 } 0131 } 0132 0133 if (requestType != Prioritized) { 0134 return NULL; 0135 } 0136 0137 for (int i = 0; i < deviceConfigs.size(); ++i) { 0138 const DvbDeviceConfig &it = deviceConfigs.at(i); 0139 0140 if ((it.device == NULL) || (it.useCount == 0) || (it.prioritizedUseCount != 0)) { 0141 continue; 0142 } 0143 0144 foreach (const DvbConfig &config, it.configs) { 0145 if (config->name == source) { 0146 deviceConfigs[i].useCount = 1; 0147 deviceConfigs[i].prioritizedUseCount = 1; 0148 deviceConfigs[i].source = source; 0149 deviceConfigs[i].transponder = transponder; 0150 0151 DvbDevice *device = it.device; 0152 device->reacquire(config.constData()); 0153 device->tune(transponder); 0154 reacquireDevice = true; 0155 return device; 0156 } 0157 } 0158 } 0159 0160 return NULL; 0161 } 0162 0163 DvbDevice *DvbManager::requestExclusiveDevice(const QString &source) 0164 { 0165 for (int i = 0; i < deviceConfigs.size(); ++i) { 0166 const DvbDeviceConfig &it = deviceConfigs.at(i); 0167 0168 if ((it.device == NULL) || (it.useCount != 0)) { 0169 continue; 0170 } 0171 0172 foreach (const DvbConfig &config, it.configs) { 0173 if (config->name == source) { 0174 DvbDevice *device = it.device; 0175 0176 if (!device->acquire(config.constData())) { 0177 continue; 0178 } 0179 0180 deviceConfigs[i].useCount = -1; 0181 deviceConfigs[i].source.clear(); 0182 return device; 0183 } 0184 } 0185 } 0186 0187 return NULL; 0188 } 0189 0190 void DvbManager::releaseDevice(DvbDevice *device, RequestType requestType) 0191 { 0192 for (int i = 0; i < deviceConfigs.size(); ++i) { 0193 const DvbDeviceConfig &it = deviceConfigs.at(i); 0194 0195 if (it.device == device) { 0196 switch (requestType) { 0197 case Prioritized: 0198 --deviceConfigs[i].prioritizedUseCount; 0199 Q_ASSERT(it.prioritizedUseCount >= 0); 0200 // fall through 0201 case Shared: 0202 --deviceConfigs[i].useCount; 0203 Q_ASSERT(it.useCount >= 0); 0204 Q_ASSERT(it.useCount >= it.prioritizedUseCount); 0205 0206 if (it.useCount == 0) { 0207 it.device->release(); 0208 } 0209 0210 break; 0211 case Exclusive: 0212 Q_ASSERT(it.useCount == -1); 0213 Q_ASSERT(it.prioritizedUseCount == 0); 0214 deviceConfigs[i].useCount = 0; 0215 it.device->release(); 0216 break; 0217 } 0218 0219 break; 0220 } 0221 } 0222 } 0223 0224 QList<DvbDeviceConfig> DvbManager::getDeviceConfigs() const 0225 { 0226 return deviceConfigs; 0227 } 0228 0229 void DvbManager::updateDeviceConfigs(const QList<DvbDeviceConfigUpdate> &configUpdates) 0230 { 0231 for (int i = 0; i < configUpdates.size(); ++i) { 0232 const DvbDeviceConfigUpdate &configUpdate = configUpdates.at(i); 0233 0234 for (int j = i;; ++j) { 0235 Q_ASSERT(j < deviceConfigs.size()); 0236 0237 if (&deviceConfigs.at(j) == configUpdate.deviceConfig) { 0238 if (i != j) { 0239 deviceConfigs.move(j, i); 0240 } 0241 0242 deviceConfigs[i].configs = configUpdate.configs; 0243 break; 0244 } 0245 } 0246 } 0247 0248 for (int i = configUpdates.size(); i < deviceConfigs.size(); ++i) { 0249 if (deviceConfigs.at(i).device != NULL) { 0250 deviceConfigs[i].configs.clear(); 0251 } else { 0252 deviceConfigs.removeAt(i); 0253 --i; 0254 } 0255 } 0256 0257 updateSourceMapping(); 0258 } 0259 0260 QDate DvbManager::getScanDataDate() 0261 { 0262 if (!scanDataDate.isValid()) { 0263 readScanData(); 0264 } 0265 0266 return scanDataDate; 0267 } 0268 0269 QStringList DvbManager::getScanSources(TransmissionType type) 0270 { 0271 if (scanData.isEmpty()) { 0272 readScanData(); 0273 } 0274 0275 return scanSources.value(type); 0276 } 0277 0278 QString DvbManager::getAutoScanSource(const QString &source) const 0279 { 0280 QPair<TransmissionType, QString> scanSource = sourceMapping.value(source); 0281 0282 if (scanSource.second.isEmpty()) { 0283 qCWarning(logDvb, "Invalid source for autoscan"); 0284 return QString(); 0285 } 0286 0287 if (((scanSource.first == DvbT) || (scanSource.first == IsdbT)) && (scanSource.second.startsWith(QLatin1String("AUTO")))) { 0288 return scanSource.second; 0289 } 0290 0291 return QString(); 0292 } 0293 0294 QList<DvbTransponder> DvbManager::getTransponders(DvbDevice *device, const QString &source) 0295 { 0296 if (scanData.isEmpty()) { 0297 readScanData(); 0298 } 0299 0300 QPair<TransmissionType, QString> scanSource = sourceMapping.value(source); 0301 0302 if (scanSource.second.isEmpty()) { 0303 qCWarning(logDvb, "Invalid source. Can't get transponder"); 0304 return QList<DvbTransponder>(); 0305 } 0306 0307 if ((scanSource.first == DvbS) && 0308 ((device->getTransmissionTypes() & DvbDevice::DvbS2) != 0)) { 0309 scanSource.first = DvbS2; 0310 } 0311 0312 if ((scanSource.first == DvbT) && 0313 ((device->getTransmissionTypes() & DvbDevice::DvbT2) != 0)) { 0314 scanSource.first = DvbT2; 0315 } 0316 0317 return scanData.value(scanSource); 0318 } 0319 0320 bool DvbManager::updateScanData(const QByteArray &data) 0321 { 0322 QByteArray uncompressed = qUncompress(data); 0323 0324 if (uncompressed.isEmpty()) { 0325 qCWarning(logDvb, "Failed to uncompress the scan data file"); 0326 return false; 0327 } 0328 0329 if (!DvbScanData(uncompressed).readDate().isValid()) { 0330 qCWarning(logDvb, "Invalid format at the scan data file"); 0331 return false; 0332 } 0333 0334 QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/scanfile.dvb")); 0335 0336 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0337 qCWarning(logDvb, "Cannot open %s", qPrintable(file.fileName())); 0338 return false; 0339 } 0340 0341 file.write(uncompressed); 0342 file.close(); 0343 0344 readScanData(); 0345 return true; 0346 } 0347 0348 QString DvbManager::getRecordingFolder() const 0349 { 0350 return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingFolder", QDir::homePath()); 0351 } 0352 0353 QString DvbManager::getTimeShiftFolder() const 0354 { 0355 return KSharedConfig::openConfig()->group("DVB").readEntry("TimeShiftFolder", QDir::homePath()); 0356 } 0357 0358 QString DvbManager::getXmltvFileName() const 0359 { 0360 return KSharedConfig::openConfig()->group("DVB").readEntry("XmltvFileName", ""); 0361 } 0362 0363 int DvbManager::getBeginMargin() const 0364 { 0365 return KSharedConfig::openConfig()->group("DVB").readEntry("BeginMargin", 300); 0366 } 0367 0368 int DvbManager::getEndMargin() const 0369 { 0370 return KSharedConfig::openConfig()->group("DVB").readEntry("EndMargin", 600); 0371 } 0372 0373 QString DvbManager::getNamingFormat() const 0374 { 0375 return KSharedConfig::openConfig()->group("DVB").readEntry("NamingFormat", "%title"); 0376 } 0377 0378 QString DvbManager::getRecordingRegex() const 0379 { 0380 return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingRegex", ""); 0381 } 0382 0383 QStringList DvbManager::getRecordingRegexList() const 0384 { 0385 return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingRegexList", QStringList()); 0386 } 0387 0388 QList<int> DvbManager::getRecordingRegexPriorityList() const 0389 { 0390 return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingRegexPriorityList", QList<int>()); 0391 } 0392 0393 QString DvbManager::getActionAfterRecording() const 0394 { 0395 return KSharedConfig::openConfig()->group("DVB").readEntry("ActionAfterRecording", ""); 0396 } 0397 0398 bool DvbManager::override6937Charset() const 0399 { 0400 return KSharedConfig::openConfig()->group("DVB").readEntry("Override6937", false); 0401 } 0402 0403 bool DvbManager::isScanWhenIdle() const 0404 { 0405 return KSharedConfig::openConfig()->group("DVB").readEntry("ScanWhenIdle", false); 0406 } 0407 0408 bool DvbManager::createInfoFile() const 0409 { 0410 return KSharedConfig::openConfig()->group("DVB").readEntry("CreateInfoFile", false); 0411 } 0412 0413 bool DvbManager::disableEpg() const 0414 { 0415 return KSharedConfig::openConfig()->group("DVB").readEntry("DisableEpg", false); 0416 } 0417 0418 void DvbManager::setRecordingFolder(const QString &path) 0419 { 0420 KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingFolder", path); 0421 } 0422 0423 void DvbManager::setTimeShiftFolder(const QString &path) 0424 { 0425 KSharedConfig::openConfig()->group("DVB").writeEntry("TimeShiftFolder", path); 0426 } 0427 0428 void DvbManager::setXmltvFileName(const QString &path) 0429 { 0430 KSharedConfig::openConfig()->group("DVB").writeEntry("XmltvFileName", path); 0431 xmlTv->clear(); 0432 xmlTv->addFile(path); 0433 } 0434 0435 void DvbManager::setBeginMargin(int beginMargin) 0436 { 0437 KSharedConfig::openConfig()->group("DVB").writeEntry("BeginMargin", beginMargin); 0438 } 0439 0440 void DvbManager::setEndMargin(int endMargin) 0441 { 0442 KSharedConfig::openConfig()->group("DVB").writeEntry("EndMargin", endMargin); 0443 } 0444 0445 void DvbManager::setNamingFormat(QString namingFormat) 0446 { 0447 KSharedConfig::openConfig()->group("DVB").writeEntry("NamingFormat", namingFormat); 0448 } 0449 0450 void DvbManager::setRecordingRegex(QString regex) 0451 { 0452 KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingRegex", regex); 0453 } 0454 0455 void DvbManager::setRecordingRegexList(const QStringList regexList) 0456 { 0457 KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingRegexList", regexList); 0458 } 0459 0460 void DvbManager::setRecordingRegexPriorityList(const QList<int> regexList) 0461 { 0462 KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingRegexPriorityList", regexList); 0463 } 0464 0465 bool DvbManager::addRecordingRegex(QString regex) 0466 { 0467 QStringList regexList = getRecordingRegexList(); 0468 regexList.append(regex); 0469 setRecordingRegexList(regexList); 0470 return true; 0471 } 0472 0473 bool DvbManager::addRecordingRegexPriority(int regexPriority) 0474 { 0475 QList<int> regexPriorityList = getRecordingRegexPriorityList(); 0476 regexPriorityList.append(regexPriority); 0477 setRecordingRegexPriorityList(regexPriorityList); 0478 return true; 0479 } 0480 0481 bool DvbManager::removeRecordingRegex(QString regex) 0482 { 0483 QStringList regexList = getRecordingRegexList(); 0484 if (regexList.contains(regex)) { 0485 regexList.removeOne(regex); 0486 setRecordingRegexList(regexList); 0487 return true; 0488 } 0489 setRecordingRegexList(regexList); 0490 return false; 0491 } 0492 0493 bool DvbManager::removeRecordingRegexPriority(int priority) 0494 { 0495 QList<int> regexPriorityList = getRecordingRegexPriorityList(); 0496 if (regexPriorityList.contains(priority)) { 0497 regexPriorityList.removeOne(priority); 0498 setRecordingRegexPriorityList(regexPriorityList); 0499 return true; 0500 } 0501 setRecordingRegexPriorityList(regexPriorityList); 0502 return false; 0503 } 0504 0505 void DvbManager::setActionAfterRecording(QString actionAfterRecording) 0506 { 0507 KSharedConfig::openConfig()->group("DVB").writeEntry("ActionAfterRecording", actionAfterRecording); 0508 } 0509 0510 void DvbManager::setOverride6937Charset(bool override) 0511 { 0512 KSharedConfig::openConfig()->group("DVB").writeEntry("Override6937", override); 0513 DvbSiText::setOverride6937(override); 0514 } 0515 0516 void DvbManager::setScanWhenIdle(bool scanWhenIdle) 0517 { 0518 KSharedConfig::openConfig()->group("DVB").writeEntry("ScanWhenIdle", scanWhenIdle); 0519 } 0520 0521 void DvbManager::setCreateInfoFile(bool createInfoFile) 0522 { 0523 KSharedConfig::openConfig()->group("DVB").writeEntry("CreateInfoFile", createInfoFile); 0524 } 0525 0526 void DvbManager::setDisableEpg(bool disableEpg) 0527 { 0528 KSharedConfig::openConfig()->group("DVB").writeEntry("DisableEpg", disableEpg); 0529 } 0530 0531 void DvbManager::enableDvbDump() 0532 { 0533 if (dvbDumpEnabled) { 0534 return; 0535 } 0536 0537 dvbDumpEnabled = true; 0538 0539 foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) { 0540 if (deviceConfig.device != NULL) { 0541 deviceConfig.device->enableDvbDump(); 0542 } 0543 } 0544 } 0545 0546 void DvbManager::requestBuiltinDeviceManager(QObject *&builtinDeviceManager) 0547 { 0548 builtinDeviceManager = new DvbLinuxDeviceManager(this); 0549 } 0550 0551 void DvbManager::deviceAdded(DvbBackendDevice *backendDevice) 0552 { 0553 DvbDevice *device = new DvbDevice(backendDevice, this); 0554 QString deviceId = device->getDeviceId(); 0555 QString frontendName = device->getFrontendName(); 0556 0557 if (dvbDumpEnabled) { 0558 device->enableDvbDump(); 0559 } 0560 0561 for (int i = 0;; ++i) { 0562 if (i == deviceConfigs.size()) { 0563 deviceConfigs.append(DvbDeviceConfig(deviceId, frontendName, device)); 0564 break; 0565 } 0566 0567 const DvbDeviceConfig &it = deviceConfigs.at(i); 0568 0569 if ((it.deviceId.isEmpty() || deviceId.isEmpty() || (it.deviceId == deviceId)) && 0570 (it.frontendName == frontendName) && (it.device == NULL)) { 0571 deviceConfigs[i].device = device; 0572 break; 0573 } 0574 } 0575 } 0576 0577 void DvbManager::deviceRemoved(DvbBackendDevice *backendDevice) 0578 { 0579 for (int i = 0; i < deviceConfigs.size(); ++i) { 0580 DvbDeviceConfig &it = deviceConfigs[i]; 0581 0582 if (it.device && it.device->getBackendDevice() == backendDevice) { 0583 if (it.useCount != 0) { 0584 it.useCount = 0; 0585 it.prioritizedUseCount = 0; 0586 it.device->release(); 0587 } 0588 0589 delete it.device; 0590 it.device = NULL; 0591 break; 0592 } 0593 } 0594 } 0595 0596 void DvbManager::loadDeviceManager() 0597 { 0598 QDir dir(QString::fromUtf8(KAFFEINE_LIB_INSTALL_DIR "/")); 0599 QStringList entries = dir.entryList(QStringList(QLatin1String("*kaffeinedvb*")), QDir::NoFilter, 0600 QDir::Name | QDir::Reversed); 0601 0602 foreach (const QString &entry, entries) { 0603 QString path = dir.filePath(entry); 0604 0605 if (!QLibrary::isLibrary(path)) { 0606 continue; 0607 } 0608 0609 QObject *deviceManager = QPluginLoader(path).instance(); 0610 0611 if (deviceManager == NULL) { 0612 qCWarning(logDvb, "Cannot load dvb device manager %s", qPrintable(path)); 0613 break; 0614 } 0615 0616 qCInfo(logDvb, "Using dvb device manager %s", qPrintable(path)); 0617 deviceManager->setParent(this); 0618 connect(deviceManager, SIGNAL(requestBuiltinDeviceManager(QObject*&)), 0619 this, SLOT(requestBuiltinDeviceManager(QObject*&))); 0620 connect(deviceManager, SIGNAL(deviceAdded(DvbBackendDevice*)), 0621 this, SLOT(deviceAdded(DvbBackendDevice*))); 0622 connect(deviceManager, SIGNAL(deviceRemoved(DvbBackendDevice*)), 0623 this, SLOT(deviceRemoved(DvbBackendDevice*))); 0624 QMetaObject::invokeMethod(deviceManager, "doColdPlug"); 0625 return; 0626 } 0627 0628 qCInfo(logDvb, "Using built-in dvb device manager"); 0629 DvbLinuxDeviceManager *deviceManager = new DvbLinuxDeviceManager(this); 0630 connect(deviceManager, SIGNAL(deviceAdded(DvbBackendDevice*)), 0631 this, SLOT(deviceAdded(DvbBackendDevice*))); 0632 connect(deviceManager, SIGNAL(deviceRemoved(DvbBackendDevice*)), 0633 this, SLOT(deviceRemoved(DvbBackendDevice*))); 0634 deviceManager->doColdPlug(); 0635 } 0636 0637 void DvbManager::readDeviceConfigs() 0638 { 0639 QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/config.dvb")); 0640 const char *errMsg; 0641 0642 if (!file.open(QIODevice::ReadOnly)) { 0643 qCWarning(logDvb, "Cannot open %s", qPrintable(file.fileName())); 0644 return; 0645 } 0646 0647 DvbDeviceConfigReader reader(&file); 0648 0649 while (!reader.atEnd()) { 0650 if (reader.readLine() != QLatin1String("[device]")) { 0651 continue; 0652 } 0653 0654 QString deviceId = reader.readString(QLatin1String("deviceId")); 0655 QString frontendName = reader.readString(QLatin1String("frontendName")); 0656 int configCount = reader.readInt(QLatin1String("configCount")); 0657 0658 if (!reader.isValid()) { 0659 errMsg = "device section invalid"; 0660 break; 0661 } 0662 0663 DvbDeviceConfig deviceConfig(deviceId, frontendName, NULL); 0664 0665 for (int i = 0; i < configCount; ++i) { 0666 while (!reader.atEnd()) { 0667 if (reader.readLine() == QLatin1String("[config]")) { 0668 break; 0669 } 0670 } 0671 0672 DvbConfigBase::TransmissionType type = 0673 reader.readEnum(QLatin1String("type"), DvbConfigBase::TransmissionTypeMax); 0674 0675 if (!reader.isValid()) { 0676 errMsg = "transmission type invalid"; 0677 break; 0678 } 0679 0680 DvbConfigBase *config = new DvbConfigBase(type); 0681 0682 config->numberOfTuners = 1; 0683 config->name = reader.readString(QLatin1String("name")); 0684 config->scanSource = reader.readString(QLatin1String("scanSource")); 0685 config->timeout = reader.readInt(QLatin1String("timeout")); 0686 0687 if (type == DvbConfigBase::DvbS) { 0688 config->latitude = 0; 0689 config->longitude = 0; 0690 config->higherVoltage = Qt::PartiallyChecked; 0691 config->configuration = reader.readEnum(QLatin1String("configuration"), 0692 DvbConfigBase::ConfigurationMax); 0693 config->lnbNumber = reader.readInt(QLatin1String("lnbNumber")); 0694 config->currentLnb.alias = reader.readString(QLatin1String("lnb")); 0695 config->higherVoltage = reader.readInt(QLatin1String("higherVoltage")); 0696 if (config->configuration == DvbConfigBase::UsalsRotor) { 0697 config->latitude = reader.readDouble(QLatin1String("latitude")); 0698 config->longitude = reader.readInt(QLatin1String("longitude")); 0699 } 0700 } 0701 0702 if (!reader.isValid()) { 0703 errMsg = "DVB device data invalid"; 0704 delete config; 0705 break; 0706 } 0707 0708 deviceConfig.configs.append(DvbConfig(config)); 0709 } 0710 0711 deviceConfigs.append(deviceConfig); 0712 } 0713 0714 if (!reader.isValid()) 0715 qCWarning(logDvb, "Found some problems at %s: %s", qPrintable(file.fileName()), errMsg); 0716 } 0717 0718 void DvbManager::writeDeviceConfigs() 0719 { 0720 QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/config.dvb")); 0721 0722 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0723 qCWarning(logDvb, "Cannot open %s", qPrintable(file.fileName())); 0724 return; 0725 } 0726 0727 DvbDeviceConfigWriter writer(&file); 0728 0729 foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) { 0730 writer.write(QLatin1String("[device]")); 0731 writer.write(QLatin1String("deviceId"), deviceConfig.deviceId); 0732 writer.write(QLatin1String("frontendName"), deviceConfig.frontendName); 0733 writer.write(QLatin1String("configCount"), deviceConfig.configs.size()); 0734 0735 for (int i = 0; i < deviceConfig.configs.size(); ++i) { 0736 const DvbConfig &config = deviceConfig.configs.at(i); 0737 writer.write(QLatin1String("[config]")); 0738 writer.write(QLatin1String("type"), config->getTransmissionType()); 0739 writer.write(QLatin1String("name"), config->name); 0740 writer.write(QLatin1String("scanSource"), config->scanSource); 0741 writer.write(QLatin1String("timeout"), config->timeout); 0742 0743 if (config->getTransmissionType() == DvbConfigBase::DvbS) { 0744 writer.write(QLatin1String("configuration"), config->configuration); 0745 writer.write(QLatin1String("lnbNumber"), config->lnbNumber); 0746 writer.write(QLatin1String("lnb"), config->currentLnb.alias); 0747 writer.write(QLatin1String("higherVoltage"), config->higherVoltage); 0748 if (config->configuration == DvbConfigBase::UsalsRotor) { 0749 writer.write(QLatin1String("latitude"), config->latitude); 0750 writer.write(QLatin1String("longitude"), config->longitude); 0751 } 0752 } 0753 } 0754 } 0755 } 0756 0757 void DvbManager::updateSourceMapping() 0758 { 0759 sourceMapping.clear(); 0760 0761 foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) { 0762 for (int i = 0; i < deviceConfig.configs.size(); ++i) { 0763 const DvbConfig &config = deviceConfig.configs.at(i); 0764 TransmissionType type; 0765 0766 switch (config->getTransmissionType()) { 0767 case DvbConfigBase::DvbC: 0768 type = DvbC; 0769 break; 0770 case DvbConfigBase::DvbS: 0771 type = DvbS; 0772 break; 0773 case DvbConfigBase::DvbT: 0774 type = DvbT; 0775 break; 0776 case DvbConfigBase::Atsc: 0777 type = Atsc; 0778 break; 0779 case DvbConfigBase::IsdbT: 0780 type = IsdbT; 0781 break; 0782 default: 0783 Q_ASSERT(false); 0784 continue; 0785 } 0786 0787 sourceMapping.insert(config->name, qMakePair(type, config->scanSource)); 0788 } 0789 } 0790 0791 sources = sourceMapping.keys(); 0792 } 0793 0794 void DvbManager::readScanData() 0795 { 0796 scanSources.clear(); 0797 scanData.clear(); 0798 0799 QFile globalFile(QString::fromUtf8(KAFFEINE_DATA_INSTALL_DIR "/kaffeine/scanfile.dvb")); 0800 QDate globalDate; 0801 0802 if (globalFile.open(QIODevice::ReadOnly)) { 0803 globalDate = DvbScanData(globalFile.read(1024)).readDate(); 0804 0805 if (globalDate.isNull()) { 0806 qCWarning(logDvb, "Cannot parse %s", qPrintable(globalFile.fileName())); 0807 } 0808 0809 globalFile.close(); 0810 } else { 0811 qCWarning(logDvb, "Cannot open global scanfile %s", qPrintable(globalFile.fileName())); 0812 } 0813 0814 QFile localFile(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/scanfile.dvb")); 0815 QByteArray localData; 0816 QDate localDate; 0817 0818 if (localFile.open(QIODevice::ReadOnly)) { 0819 localData = localFile.readAll(); 0820 localDate = DvbScanData(localData).readDate(); 0821 0822 if (localDate.isNull()) { 0823 qCWarning(logDvb, "Cannot parse %s", qPrintable(localFile.fileName())); 0824 } 0825 0826 localFile.close(); 0827 } 0828 0829 if (localDate < globalDate) { 0830 localData.clear(); 0831 0832 if (localFile.exists() && !localFile.remove()) { 0833 qCWarning(logDvb, "Cannot remove %s", qPrintable(localFile.fileName())); 0834 } 0835 0836 if (!globalFile.copy(localFile.fileName())) { 0837 qCWarning(logDvb, "Cannot copy %s to %s", qPrintable(globalFile.fileName()), qPrintable(localFile.fileName())); 0838 } 0839 0840 if (localFile.open(QIODevice::ReadOnly)) { 0841 localData = localFile.readAll(); 0842 localFile.close(); 0843 } else { 0844 qCWarning(logDvb, "Cannot open %s", qPrintable(localFile.fileName())); 0845 scanDataDate = QDate(1900, 1, 1); 0846 return; 0847 } 0848 } 0849 0850 DvbScanData data(localData); 0851 scanDataDate = data.readDate(); 0852 0853 if (!scanDataDate.isValid()) { 0854 qCWarning(logDvb, "Cannot parse %s", qPrintable(localFile.fileName())); 0855 scanDataDate = QDate(1900, 1, 1); 0856 return; 0857 } 0858 0859 // Parse scan file 0860 0861 QRegularExpression rejex = QRegularExpression("\\[(\\S+)/(\\S+)\\]"); 0862 QRegularExpressionMatch match; 0863 TransmissionType type; 0864 0865 while (!data.checkEnd()) { 0866 const char *line = data.readLine(); 0867 0868 // Discard empty lines 0869 if (*line == 0) 0870 continue; 0871 0872 QString qLine(line); 0873 0874 if (!qLine.contains(rejex, &match)) { 0875 qCWarning(logDvb, "Unrecognized line: '%s'", line); 0876 continue; 0877 0878 } 0879 0880 QString typeStr = match.captured(1); 0881 QString name = match.captured(2); 0882 0883 if (!typeStr.compare("dvb-c", Qt::CaseInsensitive)) 0884 type = DvbC; 0885 else if (!typeStr.compare("dvb-s", Qt::CaseInsensitive)) 0886 type = DvbS; 0887 else if (!typeStr.compare("dvb-t", Qt::CaseInsensitive)) 0888 type = DvbT; 0889 else if (!typeStr.compare("atsc", Qt::CaseInsensitive)) 0890 type = Atsc; 0891 else if (!typeStr.compare("isdb-t", Qt::CaseInsensitive)) 0892 type = IsdbT; 0893 else { 0894 qCWarning(logDvb, "Transmission type '%s' unknown", qPrintable(typeStr)); 0895 continue; 0896 } 0897 0898 QList<DvbTransponder> transponders; 0899 bool containsDvbS1 = false; 0900 bool containsDvbT1 = false; 0901 0902 while (!data.checkEnd()) { 0903 line = data.getLine(); 0904 0905 if ((*line == '[') || (*line == 0)) { 0906 break; 0907 } 0908 0909 line = data.readLine(); 0910 0911 // Ignore lines with empty strings 0912 if (*line == 0) 0913 continue; 0914 0915 DvbTransponder transponder = 0916 DvbTransponder::fromString(QString::fromLatin1(line)); 0917 0918 if (!transponder.isValid()) { 0919 qCWarning(logDvb, "Error parsing line : '%s'", qPrintable(line)); 0920 } else { 0921 transponders.append(transponder); 0922 0923 if (transponder.getTransmissionType() == 0924 DvbTransponderBase::DvbS) { 0925 containsDvbS1 = true; 0926 } 0927 if (transponder.getTransmissionType() == 0928 DvbTransponderBase::DvbT) { 0929 containsDvbT1 = true; 0930 } 0931 } 0932 } 0933 0934 if (type == DvbS || type == DvbS2) { 0935 scanSources[DvbS2].append(name); 0936 scanData.insert(qMakePair(DvbS2, name), transponders); 0937 0938 if (containsDvbS1) { 0939 for (int i = 0; i < transponders.size(); ++i) { 0940 if (transponders.at(i).getTransmissionType() == 0941 DvbTransponderBase::DvbS2) { 0942 transponders.removeAt(i); 0943 --i; 0944 } 0945 } 0946 0947 scanSources[DvbS].append(name); 0948 scanData.insert(qMakePair(DvbS, name), transponders); 0949 } 0950 } else if (type == DvbT || type == DvbT2) { 0951 scanSources[DvbT2].append(name); 0952 scanData.insert(qMakePair(DvbT2, name), transponders); 0953 0954 if (containsDvbT1) { 0955 for (int i = 0; i < transponders.size(); ++i) { 0956 if (transponders.at(i).getTransmissionType() == 0957 DvbTransponderBase::DvbT2) { 0958 transponders.removeAt(i); 0959 --i; 0960 } 0961 } 0962 0963 scanSources[DvbT].append(name); 0964 scanData.insert(qMakePair(DvbT, name), transponders); 0965 } 0966 } else { 0967 scanSources[type].append(name); 0968 scanData.insert(qMakePair(type, name), transponders); 0969 } 0970 } 0971 0972 if (!data.checkEnd()) 0973 qCWarning(logDvb, "Some data at the scan file were not parsed"); 0974 } 0975 0976 DvbDeviceConfig::DvbDeviceConfig(const QString &deviceId_, const QString &frontendName_, 0977 DvbDevice *device_) : deviceId(deviceId_), frontendName(frontendName_), device(device_), 0978 useCount(0), prioritizedUseCount(0) 0979 { 0980 } 0981 0982 DvbDeviceConfig::~DvbDeviceConfig() 0983 { 0984 } 0985 0986 DvbDeviceConfigUpdate::DvbDeviceConfigUpdate(const DvbDeviceConfig *deviceConfig_) : 0987 deviceConfig(deviceConfig_) 0988 { 0989 } 0990 0991 DvbDeviceConfigUpdate::~DvbDeviceConfigUpdate() 0992 { 0993 } 0994 0995 DvbScanData::DvbScanData(const QByteArray &data_) : data(data_) 0996 { 0997 begin = data.begin(); 0998 pos = data.begin(); 0999 end = data.constEnd(); 1000 } 1001 1002 DvbScanData::~DvbScanData() 1003 { 1004 } 1005 1006 bool DvbScanData::checkEnd() const 1007 { 1008 return (pos == end); 1009 } 1010 1011 const char *DvbScanData::getLine() const 1012 { 1013 return pos; 1014 } 1015 1016 const char *DvbScanData::readLine() 1017 { 1018 // ignore comments 1019 1020 while (*pos == '#') { 1021 do { 1022 ++pos; 1023 1024 if (pos == end) { 1025 return end; 1026 } 1027 } while (*pos != '\n'); 1028 1029 ++pos; 1030 } 1031 1032 char *line = pos; 1033 1034 while (pos < end) { 1035 if (*pos == ' ') 1036 ++pos; 1037 if (*pos == '\n') { 1038 *pos = 0; 1039 ++pos; 1040 break; 1041 } 1042 1043 ++pos; 1044 } 1045 1046 return line; 1047 } 1048 1049 QDate DvbScanData::readDate() 1050 { 1051 if (strcmp(readLine(), "[date]") != 0) { 1052 return QDate(); 1053 } 1054 1055 return QDate::fromString(QString::fromLatin1(readLine()), Qt::ISODate); 1056 } 1057 1058 #include "moc_dvbmanager.cpp"