"Fossies" - the Fresh Open Source Software Archive

Member "kaffeine-2.0.18/src/dvb/dvbmanager.cpp" (14 May 2019, 27086 Bytes) of package /linux/misc/kaffeine-2.0.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dvbmanager.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.0.16_vs_2.0.17.

    1 /*
    2  * dvbmanager.cpp
    3  *
    4  * Copyright (C) 2008-2011 Christoph Pfister <christophpfister@gmail.com>
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation; either version 2 of the License, or
    9  * (at your option) any later version.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License along
   17  * with this program; if not, write to the Free Software Foundation, Inc.,
   18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   19  */
   20 
   21 #include "../log.h"
   22 
   23 #include <config-kaffeine.h>
   24 #include <KConfigGroup>
   25 #include <KSharedConfig>
   26 #include <QDir>
   27 #include <QPluginLoader>
   28 #include <QRegularExpressionMatch>
   29 #include <QStandardPaths>
   30 
   31 #include "dvbconfig.h"
   32 #include "dvbdevice.h"
   33 #include "dvbdevice_linux.h"
   34 #include "dvbepg.h"
   35 #include "dvbliveview.h"
   36 #include "dvbmanager.h"
   37 #include "dvbmanager_p.h"
   38 #include "dvbsi.h"
   39 #include "xmltv.h"
   40 
   41 DvbManager::DvbManager(MediaWidget *mediaWidget_, QWidget *parent_) : QObject(parent_),
   42     parent(parent_), mediaWidget(mediaWidget_), channelView(NULL), dvbDumpEnabled(false)
   43 {
   44     channelModel = DvbChannelModel::createSqlModel(this);
   45     recordingModel = new DvbRecordingModel(this, this);
   46     epgModel = new DvbEpgModel(this, this);
   47     liveView = new DvbLiveView(this, this);
   48     xmlTv = new XmlTv(this);
   49 
   50     readDeviceConfigs();
   51     updateSourceMapping();
   52 
   53     loadDeviceManager();
   54 
   55     DvbSiText::setOverride6937(override6937Charset());
   56 
   57     QString xmlFile = getXmltvFileName();
   58 
   59     if (xmlFile != "")
   60         xmlTv->addFile(xmlFile);
   61 }
   62 
   63 DvbManager::~DvbManager()
   64 {
   65     writeDeviceConfigs();
   66 
   67     // we need an explicit deletion order (device users ; devices ; device manager)
   68 
   69     delete xmlTv;
   70     delete epgModel;
   71     epgModel = NULL;
   72     delete recordingModel;
   73 
   74     foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) {
   75         delete deviceConfig.device;
   76     }
   77 }
   78 
   79 DvbDevice *DvbManager::requestDevice(const QString &source, const DvbTransponder &transponder,
   80     DvbManager::RequestType requestType)
   81 {
   82     Q_ASSERT(requestType != Exclusive);
   83     // FIXME call DvbEpgModel::startEventFilter / DvbEpgModel::stopEventFilter here?
   84 
   85     reacquireDevice = false;
   86     for (int i = 0; i < deviceConfigs.size(); ++i) {
   87         const DvbDeviceConfig &it = deviceConfigs.at(i);
   88 
   89         if ((it.device == NULL) || (it.useCount < 1)) {
   90             continue;
   91         }
   92 
   93         if ((it.source == source) && it.transponder.corresponds(transponder)) {
   94             ++deviceConfigs[i].useCount;
   95 
   96             if (requestType == Prioritized) {
   97                 ++deviceConfigs[i].prioritizedUseCount;
   98             }
   99 
  100             return it.device;
  101         }
  102     }
  103 
  104     for (int i = 0; i < deviceConfigs.size(); ++i) {
  105         const DvbDeviceConfig &it = deviceConfigs.at(i);
  106 
  107         if ((it.device == NULL) || (it.useCount != 0)) {
  108             continue;
  109         }
  110 
  111         foreach (const DvbConfig &config, it.configs) {
  112             if (config->name == source) {
  113                 DvbDevice *device = it.device;
  114 
  115                 if (!device->acquire(config.constData())) {
  116                     continue;
  117                 }
  118 
  119                 deviceConfigs[i].useCount = 1;
  120 
  121                 if (requestType == Prioritized) {
  122                     deviceConfigs[i].prioritizedUseCount = 1;
  123                 }
  124 
  125                 deviceConfigs[i].source = source;
  126                 deviceConfigs[i].transponder = transponder;
  127                 device->tune(transponder);
  128                 return device;
  129             }
  130         }
  131     }
  132 
  133     if (requestType != Prioritized) {
  134         return NULL;
  135     }
  136 
  137     for (int i = 0; i < deviceConfigs.size(); ++i) {
  138         const DvbDeviceConfig &it = deviceConfigs.at(i);
  139 
  140         if ((it.device == NULL) || (it.useCount == 0) || (it.prioritizedUseCount != 0)) {
  141             continue;
  142         }
  143 
  144         foreach (const DvbConfig &config, it.configs) {
  145             if (config->name == source) {
  146                 deviceConfigs[i].useCount = 1;
  147                 deviceConfigs[i].prioritizedUseCount = 1;
  148                 deviceConfigs[i].source = source;
  149                 deviceConfigs[i].transponder = transponder;
  150 
  151                 DvbDevice *device = it.device;
  152                 device->reacquire(config.constData());
  153                 device->tune(transponder);
  154                 reacquireDevice = true;
  155                 return device;
  156             }
  157         }
  158     }
  159 
  160     return NULL;
  161 }
  162 
  163 DvbDevice *DvbManager::requestExclusiveDevice(const QString &source)
  164 {
  165     for (int i = 0; i < deviceConfigs.size(); ++i) {
  166         const DvbDeviceConfig &it = deviceConfigs.at(i);
  167 
  168         if ((it.device == NULL) || (it.useCount != 0)) {
  169             continue;
  170         }
  171 
  172         foreach (const DvbConfig &config, it.configs) {
  173             if (config->name == source) {
  174                 DvbDevice *device = it.device;
  175 
  176                 if (!device->acquire(config.constData())) {
  177                     continue;
  178                 }
  179 
  180                 deviceConfigs[i].useCount = -1;
  181                 deviceConfigs[i].source.clear();
  182                 return device;
  183             }
  184         }
  185     }
  186 
  187     return NULL;
  188 }
  189 
  190 void DvbManager::releaseDevice(DvbDevice *device, RequestType requestType)
  191 {
  192     for (int i = 0; i < deviceConfigs.size(); ++i) {
  193         const DvbDeviceConfig &it = deviceConfigs.at(i);
  194 
  195         if (it.device == device) {
  196             switch (requestType) {
  197             case Prioritized:
  198                 --deviceConfigs[i].prioritizedUseCount;
  199                 Q_ASSERT(it.prioritizedUseCount >= 0);
  200             // fall through
  201             case Shared:
  202                 --deviceConfigs[i].useCount;
  203                 Q_ASSERT(it.useCount >= 0);
  204                 Q_ASSERT(it.useCount >= it.prioritizedUseCount);
  205 
  206                 if (it.useCount == 0) {
  207                     it.device->release();
  208                 }
  209 
  210                 break;
  211             case Exclusive:
  212                 Q_ASSERT(it.useCount == -1);
  213                 Q_ASSERT(it.prioritizedUseCount == 0);
  214                 deviceConfigs[i].useCount = 0;
  215                 it.device->release();
  216                 break;
  217             }
  218 
  219             break;
  220         }
  221     }
  222 }
  223 
  224 QList<DvbDeviceConfig> DvbManager::getDeviceConfigs() const
  225 {
  226     return deviceConfigs;
  227 }
  228 
  229 void DvbManager::updateDeviceConfigs(const QList<DvbDeviceConfigUpdate> &configUpdates)
  230 {
  231     for (int i = 0; i < configUpdates.size(); ++i) {
  232         const DvbDeviceConfigUpdate &configUpdate = configUpdates.at(i);
  233 
  234         for (int j = i;; ++j) {
  235             Q_ASSERT(j < deviceConfigs.size());
  236 
  237             if (&deviceConfigs.at(j) == configUpdate.deviceConfig) {
  238                 if (i != j) {
  239                     deviceConfigs.move(j, i);
  240                 }
  241 
  242                 deviceConfigs[i].configs = configUpdate.configs;
  243                 break;
  244             }
  245         }
  246     }
  247 
  248     for (int i = configUpdates.size(); i < deviceConfigs.size(); ++i) {
  249         if (deviceConfigs.at(i).device != NULL) {
  250             deviceConfigs[i].configs.clear();
  251         } else {
  252             deviceConfigs.removeAt(i);
  253             --i;
  254         }
  255     }
  256 
  257     updateSourceMapping();
  258 }
  259 
  260 QDate DvbManager::getScanDataDate()
  261 {
  262     if (!scanDataDate.isValid()) {
  263         readScanData();
  264     }
  265 
  266     return scanDataDate;
  267 }
  268 
  269 QStringList DvbManager::getScanSources(TransmissionType type)
  270 {
  271     if (scanData.isEmpty()) {
  272         readScanData();
  273     }
  274 
  275     return scanSources.value(type);
  276 }
  277 
  278 QString DvbManager::getAutoScanSource(const QString &source) const
  279 {
  280     QPair<TransmissionType, QString> scanSource = sourceMapping.value(source);
  281 
  282     if (scanSource.second.isEmpty()) {
  283         qCWarning(logDvb, "Invalid source for autoscan");
  284         return QString();
  285     }
  286 
  287     if (((scanSource.first == DvbT) || (scanSource.first == IsdbT)) && (scanSource.second.startsWith(QLatin1String("AUTO")))) {
  288         return scanSource.second;
  289     }
  290 
  291     return QString();
  292 }
  293 
  294 QList<DvbTransponder> DvbManager::getTransponders(DvbDevice *device, const QString &source)
  295 {
  296     if (scanData.isEmpty()) {
  297         readScanData();
  298     }
  299 
  300     QPair<TransmissionType, QString> scanSource = sourceMapping.value(source);
  301 
  302     if (scanSource.second.isEmpty()) {
  303         qCWarning(logDvb, "Invalid source. Can't get transponder");
  304         return QList<DvbTransponder>();
  305     }
  306 
  307     if ((scanSource.first == DvbS) &&
  308         ((device->getTransmissionTypes() & DvbDevice::DvbS2) != 0)) {
  309         scanSource.first = DvbS2;
  310     }
  311 
  312     if ((scanSource.first == DvbT) &&
  313         ((device->getTransmissionTypes() & DvbDevice::DvbT2) != 0)) {
  314         scanSource.first = DvbT2;
  315     }
  316 
  317     return scanData.value(scanSource);
  318 }
  319 
  320 bool DvbManager::updateScanData(const QByteArray &data)
  321 {
  322     QByteArray uncompressed = qUncompress(data);
  323 
  324     if (uncompressed.isEmpty()) {
  325         qCWarning(logDvb, "Failed to uncompress the scan data file");
  326         return false;
  327     }
  328 
  329     if (!DvbScanData(uncompressed).readDate().isValid()) {
  330         qCWarning(logDvb, "Invalid format at the scan data file");
  331         return false;
  332     }
  333 
  334     QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/scanfile.dvb"));
  335 
  336     if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
  337         qCWarning(logDvb, "Cannot open %s", qPrintable(file.fileName()));
  338         return false;
  339     }
  340 
  341     file.write(uncompressed);
  342     file.close();
  343 
  344     readScanData();
  345     return true;
  346 }
  347 
  348 QString DvbManager::getRecordingFolder() const
  349 {
  350     return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingFolder", QDir::homePath());
  351 }
  352 
  353 QString DvbManager::getTimeShiftFolder() const
  354 {
  355     return KSharedConfig::openConfig()->group("DVB").readEntry("TimeShiftFolder", QDir::homePath());
  356 }
  357 
  358 QString DvbManager::getXmltvFileName() const
  359 {
  360     return KSharedConfig::openConfig()->group("DVB").readEntry("XmltvFileName", "");
  361 }
  362 
  363 int DvbManager::getBeginMargin() const
  364 {
  365     return KSharedConfig::openConfig()->group("DVB").readEntry("BeginMargin", 300);
  366 }
  367 
  368 int DvbManager::getEndMargin() const
  369 {
  370     return KSharedConfig::openConfig()->group("DVB").readEntry("EndMargin", 600);
  371 }
  372 
  373 QString DvbManager::getNamingFormat() const
  374 {
  375     return KSharedConfig::openConfig()->group("DVB").readEntry("NamingFormat", "%title");
  376 }
  377 
  378 QString DvbManager::getRecordingRegex() const
  379 {
  380     return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingRegex", "");
  381 }
  382 
  383 QStringList DvbManager::getRecordingRegexList() const
  384 {
  385     return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingRegexList", QStringList());
  386 }
  387 
  388 QList<int> DvbManager::getRecordingRegexPriorityList() const
  389 {
  390     return KSharedConfig::openConfig()->group("DVB").readEntry("RecordingRegexPriorityList", QList<int>());
  391 }
  392 
  393 QString DvbManager::getActionAfterRecording() const
  394 {
  395     return KSharedConfig::openConfig()->group("DVB").readEntry("ActionAfterRecording", "");
  396 }
  397 
  398 bool DvbManager::override6937Charset() const
  399 {
  400     return KSharedConfig::openConfig()->group("DVB").readEntry("Override6937", false);
  401 }
  402 
  403 bool DvbManager::isScanWhenIdle() const
  404 {
  405     return KSharedConfig::openConfig()->group("DVB").readEntry("ScanWhenIdle", false);
  406 }
  407 
  408 bool DvbManager::createInfoFile() const
  409 {
  410     return KSharedConfig::openConfig()->group("DVB").readEntry("CreateInfoFile", false);
  411 }
  412 
  413 bool DvbManager::disableEpg() const
  414 {
  415     return KSharedConfig::openConfig()->group("DVB").readEntry("DisableEpg", false);
  416 }
  417 
  418 void DvbManager::setRecordingFolder(const QString &path)
  419 {
  420     KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingFolder", path);
  421 }
  422 
  423 void DvbManager::setTimeShiftFolder(const QString &path)
  424 {
  425     KSharedConfig::openConfig()->group("DVB").writeEntry("TimeShiftFolder", path);
  426 }
  427 
  428 void DvbManager::setXmltvFileName(const QString &path)
  429 {
  430     KSharedConfig::openConfig()->group("DVB").writeEntry("XmltvFileName", path);
  431     xmlTv->clear();
  432     xmlTv->addFile(path);
  433 }
  434 
  435 void DvbManager::setBeginMargin(int beginMargin)
  436 {
  437     KSharedConfig::openConfig()->group("DVB").writeEntry("BeginMargin", beginMargin);
  438 }
  439 
  440 void DvbManager::setEndMargin(int endMargin)
  441 {
  442     KSharedConfig::openConfig()->group("DVB").writeEntry("EndMargin", endMargin);
  443 }
  444 
  445 void DvbManager::setNamingFormat(QString namingFormat)
  446 {
  447     KSharedConfig::openConfig()->group("DVB").writeEntry("NamingFormat", namingFormat);
  448 }
  449 
  450 void DvbManager::setRecordingRegex(QString regex)
  451 {
  452     KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingRegex", regex);
  453 }
  454 
  455 void DvbManager::setRecordingRegexList(const QStringList regexList)
  456 {
  457     KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingRegexList", regexList);
  458 }
  459 
  460 void DvbManager::setRecordingRegexPriorityList(const QList<int> regexList)
  461 {
  462     KSharedConfig::openConfig()->group("DVB").writeEntry("RecordingRegexPriorityList", regexList);
  463 }
  464 
  465 bool DvbManager::addRecordingRegex(QString regex)
  466 {
  467     QStringList regexList = getRecordingRegexList();
  468     regexList.append(regex);
  469     setRecordingRegexList(regexList);
  470     return true;
  471 }
  472 
  473 bool DvbManager::addRecordingRegexPriority(int regexPriority)
  474 {
  475     QList<int> regexPriorityList = getRecordingRegexPriorityList();
  476     regexPriorityList.append(regexPriority);
  477     setRecordingRegexPriorityList(regexPriorityList);
  478     return true;
  479 }
  480 
  481 bool DvbManager::removeRecordingRegex(QString regex)
  482 {
  483     QStringList regexList = getRecordingRegexList();
  484     if (regexList.contains(regex)) {
  485         regexList.removeOne(regex);
  486         setRecordingRegexList(regexList);
  487         return true;
  488     }
  489     setRecordingRegexList(regexList);
  490     return false;
  491 }
  492 
  493 bool DvbManager::removeRecordingRegexPriority(int priority)
  494 {
  495     QList<int> regexPriorityList = getRecordingRegexPriorityList();
  496     if (regexPriorityList.contains(priority)) {
  497         regexPriorityList.removeOne(priority);
  498         setRecordingRegexPriorityList(regexPriorityList);
  499         return true;
  500     }
  501     setRecordingRegexPriorityList(regexPriorityList);
  502     return false;
  503 }
  504 
  505 void DvbManager::setActionAfterRecording(QString actionAfterRecording)
  506 {
  507     KSharedConfig::openConfig()->group("DVB").writeEntry("ActionAfterRecording", actionAfterRecording);
  508 }
  509 
  510 void DvbManager::setOverride6937Charset(bool override)
  511 {
  512     KSharedConfig::openConfig()->group("DVB").writeEntry("Override6937", override);
  513     DvbSiText::setOverride6937(override);
  514 }
  515 
  516 void DvbManager::setScanWhenIdle(bool scanWhenIdle)
  517 {
  518     KSharedConfig::openConfig()->group("DVB").writeEntry("ScanWhenIdle", scanWhenIdle);
  519 }
  520 
  521 void DvbManager::setCreateInfoFile(bool createInfoFile)
  522 {
  523     KSharedConfig::openConfig()->group("DVB").writeEntry("CreateInfoFile", createInfoFile);
  524 }
  525 
  526 void DvbManager::setDisableEpg(bool disableEpg)
  527 {
  528     KSharedConfig::openConfig()->group("DVB").writeEntry("DisableEpg", disableEpg);
  529 }
  530 
  531 void DvbManager::enableDvbDump()
  532 {
  533     if (dvbDumpEnabled) {
  534         return;
  535     }
  536 
  537     dvbDumpEnabled = true;
  538 
  539     foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) {
  540         if (deviceConfig.device != NULL) {
  541             deviceConfig.device->enableDvbDump();
  542         }
  543     }
  544 }
  545 
  546 void DvbManager::requestBuiltinDeviceManager(QObject *&builtinDeviceManager)
  547 {
  548     builtinDeviceManager = new DvbLinuxDeviceManager(this);
  549 }
  550 
  551 void DvbManager::deviceAdded(DvbBackendDevice *backendDevice)
  552 {
  553     DvbDevice *device = new DvbDevice(backendDevice, this);
  554     QString deviceId = device->getDeviceId();
  555     QString frontendName = device->getFrontendName();
  556 
  557     if (dvbDumpEnabled) {
  558         device->enableDvbDump();
  559     }
  560 
  561     for (int i = 0;; ++i) {
  562         if (i == deviceConfigs.size()) {
  563             deviceConfigs.append(DvbDeviceConfig(deviceId, frontendName, device));
  564             break;
  565         }
  566 
  567         const DvbDeviceConfig &it = deviceConfigs.at(i);
  568 
  569         if ((it.deviceId.isEmpty() || deviceId.isEmpty() || (it.deviceId == deviceId)) &&
  570             (it.frontendName == frontendName) && (it.device == NULL)) {
  571             deviceConfigs[i].device = device;
  572             break;
  573         }
  574     }
  575 }
  576 
  577 void DvbManager::deviceRemoved(DvbBackendDevice *backendDevice)
  578 {
  579     for (int i = 0; i < deviceConfigs.size(); ++i) {
  580         DvbDeviceConfig &it = deviceConfigs[i];
  581 
  582         if (it.device && it.device->getBackendDevice() == backendDevice) {
  583             if (it.useCount != 0) {
  584                 it.useCount = 0;
  585                 it.prioritizedUseCount = 0;
  586                 it.device->release();
  587             }
  588 
  589             delete it.device;
  590             it.device = NULL;
  591             break;
  592         }
  593     }
  594 }
  595 
  596 void DvbManager::loadDeviceManager()
  597 {
  598     QDir dir(QString::fromUtf8(KAFFEINE_LIB_INSTALL_DIR "/"));
  599     QStringList entries = dir.entryList(QStringList(QLatin1String("*kaffeinedvb*")), QDir::NoFilter,
  600         QDir::Name | QDir::Reversed);
  601 
  602     foreach (const QString &entry, entries) {
  603         QString path = dir.filePath(entry);
  604 
  605         if (!QLibrary::isLibrary(path)) {
  606             continue;
  607         }
  608 
  609         QObject *deviceManager = QPluginLoader(path).instance();
  610 
  611         if (deviceManager == NULL) {
  612             qCWarning(logDvb, "Cannot load dvb device manager %s", qPrintable(path));
  613             break;
  614         }
  615 
  616         qCInfo(logDvb, "Using dvb device manager %s", qPrintable(path));
  617         deviceManager->setParent(this);
  618         connect(deviceManager, SIGNAL(requestBuiltinDeviceManager(QObject*&)),
  619             this, SLOT(requestBuiltinDeviceManager(QObject*&)));
  620         connect(deviceManager, SIGNAL(deviceAdded(DvbBackendDevice*)),
  621             this, SLOT(deviceAdded(DvbBackendDevice*)));
  622         connect(deviceManager, SIGNAL(deviceRemoved(DvbBackendDevice*)),
  623             this, SLOT(deviceRemoved(DvbBackendDevice*)));
  624         QMetaObject::invokeMethod(deviceManager, "doColdPlug");
  625         return;
  626     }
  627 
  628     qCInfo(logDvb, "Using built-in dvb device manager");
  629     DvbLinuxDeviceManager *deviceManager = new DvbLinuxDeviceManager(this);
  630     connect(deviceManager, SIGNAL(deviceAdded(DvbBackendDevice*)),
  631         this, SLOT(deviceAdded(DvbBackendDevice*)));
  632     connect(deviceManager, SIGNAL(deviceRemoved(DvbBackendDevice*)),
  633         this, SLOT(deviceRemoved(DvbBackendDevice*)));
  634     deviceManager->doColdPlug();
  635 }
  636 
  637 void DvbManager::readDeviceConfigs()
  638 {
  639     QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/config.dvb"));
  640     const char *errMsg;
  641 
  642     if (!file.open(QIODevice::ReadOnly)) {
  643         qCWarning(logDvb, "Cannot open %s", qPrintable(file.fileName()));
  644         return;
  645     }
  646 
  647     DvbDeviceConfigReader reader(&file);
  648 
  649     while (!reader.atEnd()) {
  650         if (reader.readLine() != QLatin1String("[device]")) {
  651             continue;
  652         }
  653 
  654         QString deviceId = reader.readString(QLatin1String("deviceId"));
  655         QString frontendName = reader.readString(QLatin1String("frontendName"));
  656         int configCount = reader.readInt(QLatin1String("configCount"));
  657 
  658         if (!reader.isValid()) {
  659             errMsg = "device section invalid";
  660             break;
  661         }
  662 
  663         DvbDeviceConfig deviceConfig(deviceId, frontendName, NULL);
  664 
  665         for (int i = 0; i < configCount; ++i) {
  666             while (!reader.atEnd()) {
  667                 if (reader.readLine() == QLatin1String("[config]")) {
  668                     break;
  669                 }
  670             }
  671 
  672             DvbConfigBase::TransmissionType type =
  673                 reader.readEnum(QLatin1String("type"), DvbConfigBase::TransmissionTypeMax);
  674 
  675             if (!reader.isValid()) {
  676                 errMsg = "transmission type invalid";
  677                 break;
  678             }
  679 
  680             DvbConfigBase *config = new DvbConfigBase(type);
  681 
  682             config->numberOfTuners = 1;
  683             config->name = reader.readString(QLatin1String("name"));
  684             config->scanSource = reader.readString(QLatin1String("scanSource"));
  685             config->timeout = reader.readInt(QLatin1String("timeout"));
  686 
  687             if (type == DvbConfigBase::DvbS) {
  688                 config->latitude = 0;
  689                 config->longitude = 0;
  690                 config->higherVoltage = Qt::PartiallyChecked;
  691                 config->configuration = reader.readEnum(QLatin1String("configuration"),
  692                     DvbConfigBase::ConfigurationMax);
  693                 config->lnbNumber = reader.readInt(QLatin1String("lnbNumber"));
  694                 config->currentLnb.alias = reader.readString(QLatin1String("lnb"));
  695                 config->higherVoltage = reader.readInt(QLatin1String("higherVoltage"));
  696                 if (config->configuration == DvbConfigBase::UsalsRotor) {
  697                     config->latitude = reader.readDouble(QLatin1String("latitude"));
  698                     config->longitude = reader.readInt(QLatin1String("longitude"));
  699                 }
  700             }
  701 
  702             if (!reader.isValid()) {
  703                 errMsg = "DVB device data invalid";
  704                 delete config;
  705                 break;
  706             }
  707 
  708             deviceConfig.configs.append(DvbConfig(config));
  709         }
  710 
  711         deviceConfigs.append(deviceConfig);
  712     }
  713 
  714     if (!reader.isValid())
  715         qCWarning(logDvb, "Found some problems at %s: %s", qPrintable(file.fileName()), errMsg);
  716 }
  717 
  718 void DvbManager::writeDeviceConfigs()
  719 {
  720     QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/config.dvb"));
  721 
  722     if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
  723         qCWarning(logDvb, "Cannot open %s", qPrintable(file.fileName()));
  724         return;
  725     }
  726 
  727     DvbDeviceConfigWriter writer(&file);
  728 
  729     foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) {
  730         writer.write(QLatin1String("[device]"));
  731         writer.write(QLatin1String("deviceId"), deviceConfig.deviceId);
  732         writer.write(QLatin1String("frontendName"), deviceConfig.frontendName);
  733         writer.write(QLatin1String("configCount"), deviceConfig.configs.size());
  734 
  735         for (int i = 0; i < deviceConfig.configs.size(); ++i) {
  736             const DvbConfig &config = deviceConfig.configs.at(i);
  737             writer.write(QLatin1String("[config]"));
  738             writer.write(QLatin1String("type"), config->getTransmissionType());
  739             writer.write(QLatin1String("name"), config->name);
  740             writer.write(QLatin1String("scanSource"), config->scanSource);
  741             writer.write(QLatin1String("timeout"), config->timeout);
  742 
  743             if (config->getTransmissionType() == DvbConfigBase::DvbS) {
  744                 writer.write(QLatin1String("configuration"), config->configuration);
  745                 writer.write(QLatin1String("lnbNumber"), config->lnbNumber);
  746                 writer.write(QLatin1String("lnb"), config->currentLnb.alias);
  747                 writer.write(QLatin1String("higherVoltage"), config->higherVoltage);
  748                 if (config->configuration == DvbConfigBase::UsalsRotor) {
  749                     writer.write(QLatin1String("latitude"), config->latitude);
  750                     writer.write(QLatin1String("longitude"), config->longitude);
  751                 }
  752             }
  753         }
  754     }
  755 }
  756 
  757 void DvbManager::updateSourceMapping()
  758 {
  759     sourceMapping.clear();
  760 
  761     foreach (const DvbDeviceConfig &deviceConfig, deviceConfigs) {
  762         for (int i = 0; i < deviceConfig.configs.size(); ++i) {
  763             const DvbConfig &config = deviceConfig.configs.at(i);
  764             TransmissionType type;
  765 
  766             switch (config->getTransmissionType()) {
  767             case DvbConfigBase::DvbC:
  768                 type = DvbC;
  769                 break;
  770             case DvbConfigBase::DvbS:
  771                 type = DvbS;
  772                 break;
  773             case DvbConfigBase::DvbT:
  774                 type = DvbT;
  775                 break;
  776             case DvbConfigBase::Atsc:
  777                 type = Atsc;
  778                 break;
  779             case DvbConfigBase::IsdbT:
  780                 type = IsdbT;
  781                 break;
  782             default:
  783                 Q_ASSERT(false);
  784                 continue;
  785             }
  786 
  787             sourceMapping.insert(config->name, qMakePair(type, config->scanSource));
  788         }
  789     }
  790 
  791     sources = sourceMapping.keys();
  792 }
  793 
  794 void DvbManager::readScanData()
  795 {
  796     scanSources.clear();
  797     scanData.clear();
  798 
  799     QFile globalFile(QString::fromUtf8(KAFFEINE_DATA_INSTALL_DIR "/kaffeine/scanfile.dvb"));
  800     QDate globalDate;
  801 
  802     if (globalFile.open(QIODevice::ReadOnly)) {
  803         globalDate = DvbScanData(globalFile.read(1024)).readDate();
  804 
  805         if (globalDate.isNull()) {
  806             qCWarning(logDvb, "Cannot parse %s", qPrintable(globalFile.fileName()));
  807         }
  808 
  809         globalFile.close();
  810     } else {
  811         qCWarning(logDvb, "Cannot open global scanfile %s", qPrintable(globalFile.fileName()));
  812     }
  813 
  814     QFile localFile(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/scanfile.dvb"));
  815     QByteArray localData;
  816     QDate localDate;
  817 
  818     if (localFile.open(QIODevice::ReadOnly)) {
  819         localData = localFile.readAll();
  820         localDate = DvbScanData(localData).readDate();
  821 
  822         if (localDate.isNull()) {
  823             qCWarning(logDvb, "Cannot parse %s", qPrintable(localFile.fileName()));
  824         }
  825 
  826         localFile.close();
  827     }
  828 
  829     if (localDate < globalDate) {
  830         localData.clear();
  831 
  832         if (localFile.exists() && !localFile.remove()) {
  833             qCWarning(logDvb, "Cannot remove %s", qPrintable(localFile.fileName()));
  834         }
  835 
  836         if (!globalFile.copy(localFile.fileName())) {
  837             qCWarning(logDvb, "Cannot copy %s to %s", qPrintable(globalFile.fileName()), qPrintable(localFile.fileName()));
  838         }
  839 
  840         if (localFile.open(QIODevice::ReadOnly)) {
  841             localData = localFile.readAll();
  842             localFile.close();
  843         } else {
  844             qCWarning(logDvb, "Cannot open %s", qPrintable(localFile.fileName()));
  845             scanDataDate = QDate(1900, 1, 1);
  846             return;
  847         }
  848     }
  849 
  850     DvbScanData data(localData);
  851     scanDataDate = data.readDate();
  852 
  853     if (!scanDataDate.isValid()) {
  854         qCWarning(logDvb, "Cannot parse %s", qPrintable(localFile.fileName()));
  855         scanDataDate = QDate(1900, 1, 1);
  856         return;
  857     }
  858 
  859     // Parse scan file
  860 
  861     QRegularExpression rejex = QRegularExpression("\\[(\\S+)/(\\S+)\\]");
  862     QRegularExpressionMatch match;
  863     TransmissionType type;
  864 
  865     while (!data.checkEnd()) {
  866         const char *line = data.readLine();
  867 
  868         // Discard empty lines
  869         if (*line == 0)
  870             continue;
  871 
  872         QString qLine(line);
  873 
  874         if (!qLine.contains(rejex, &match)) {
  875             qCWarning(logDvb, "Unrecognized line: '%s'", line);
  876             continue;
  877 
  878         }
  879 
  880         QString typeStr = match.captured(1);
  881         QString name = match.captured(2);
  882 
  883         if (!typeStr.compare("dvb-c", Qt::CaseInsensitive))
  884             type = DvbC;
  885         else if (!typeStr.compare("dvb-s", Qt::CaseInsensitive))
  886             type = DvbS;
  887         else if (!typeStr.compare("dvb-t", Qt::CaseInsensitive))
  888             type = DvbT;
  889         else if (!typeStr.compare("atsc", Qt::CaseInsensitive))
  890             type = Atsc;
  891         else if (!typeStr.compare("isdb-t", Qt::CaseInsensitive))
  892             type = IsdbT;
  893         else {
  894             qCWarning(logDvb, "Transmission type '%s' unknown", qPrintable(typeStr));
  895             continue;
  896         }
  897 
  898         QList<DvbTransponder> transponders;
  899         bool containsDvbS1 = false;
  900         bool containsDvbT1 = false;
  901 
  902         while (!data.checkEnd()) {
  903             line = data.getLine();
  904 
  905             if ((*line == '[') || (*line == 0)) {
  906                 break;
  907             }
  908 
  909             line = data.readLine();
  910 
  911             // Ignore lines with empty strings
  912             if (*line == 0)
  913                 continue;
  914 
  915             DvbTransponder transponder =
  916                 DvbTransponder::fromString(QString::fromLatin1(line));
  917 
  918             if (!transponder.isValid()) {
  919                 qCWarning(logDvb, "Error parsing line : '%s'", qPrintable(line));
  920             } else {
  921                 transponders.append(transponder);
  922 
  923                 if (transponder.getTransmissionType() ==
  924                     DvbTransponderBase::DvbS) {
  925                     containsDvbS1 = true;
  926                 }
  927                 if (transponder.getTransmissionType() ==
  928                     DvbTransponderBase::DvbT) {
  929                     containsDvbT1 = true;
  930                 }
  931             }
  932         }
  933 
  934         if (type == DvbS || type == DvbS2) {
  935             scanSources[DvbS2].append(name);
  936             scanData.insert(qMakePair(DvbS2, name), transponders);
  937 
  938             if (containsDvbS1) {
  939                 for (int i = 0; i < transponders.size(); ++i) {
  940                     if (transponders.at(i).getTransmissionType() ==
  941                         DvbTransponderBase::DvbS2) {
  942                         transponders.removeAt(i);
  943                         --i;
  944                     }
  945                 }
  946 
  947                 scanSources[DvbS].append(name);
  948                 scanData.insert(qMakePair(DvbS, name), transponders);
  949             }
  950         } else if (type == DvbT || type == DvbT2) {
  951             scanSources[DvbT2].append(name);
  952             scanData.insert(qMakePair(DvbT2, name), transponders);
  953 
  954             if (containsDvbT1) {
  955                 for (int i = 0; i < transponders.size(); ++i) {
  956                     if (transponders.at(i).getTransmissionType() ==
  957                         DvbTransponderBase::DvbT2) {
  958                         transponders.removeAt(i);
  959                         --i;
  960                     }
  961                 }
  962 
  963                 scanSources[DvbT].append(name);
  964                 scanData.insert(qMakePair(DvbT, name), transponders);
  965             }
  966         } else {
  967             scanSources[type].append(name);
  968             scanData.insert(qMakePair(type, name), transponders);
  969         }
  970     }
  971 
  972     if (!data.checkEnd())
  973         qCWarning(logDvb, "Some data at the scan file were not parsed");
  974 }
  975 
  976 DvbDeviceConfig::DvbDeviceConfig(const QString &deviceId_, const QString &frontendName_,
  977     DvbDevice *device_) : deviceId(deviceId_), frontendName(frontendName_), device(device_),
  978     useCount(0), prioritizedUseCount(0)
  979 {
  980 }
  981 
  982 DvbDeviceConfig::~DvbDeviceConfig()
  983 {
  984 }
  985 
  986 DvbDeviceConfigUpdate::DvbDeviceConfigUpdate(const DvbDeviceConfig *deviceConfig_) :
  987     deviceConfig(deviceConfig_)
  988 {
  989 }
  990 
  991 DvbDeviceConfigUpdate::~DvbDeviceConfigUpdate()
  992 {
  993 }
  994 
  995 DvbScanData::DvbScanData(const QByteArray &data_) : data(data_)
  996 {
  997     begin = data.begin();
  998     pos = data.begin();
  999     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 }