MythTV  master
weatherSource.cpp
Go to the documentation of this file.
1 // C++
2 #include <unistd.h>
3 
4 // QT headers
5 #include <QApplication>
6 #include <QDir>
7 #include <QFile>
8 #include <QTextStream>
9 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
10 #include <QTextCodec>
11 #else
12 #include <QStringConverter>
13 #endif
14 
15 // MythTV headers
16 #include <libmythbase/compat.h>
17 #include <libmythbase/exitcodes.h>
19 #include <libmythbase/mythdb.h>
20 #include <libmythbase/mythdirs.h>
23 
24 // MythWeather headers
25 #include "weatherScreen.h"
26 #include "weatherSource.h"
27 
28 QStringList WeatherSource::ProbeTypes(const QString& workingDirectory,
29  const QString& program)
30 {
31  QStringList arguments("-t");
32  const QString loc = QString("WeatherSource::ProbeTypes(%1 %2): ")
33  .arg(program, arguments.join(" "));
34  QStringList types;
35 
36  uint flags = kMSRunShell | kMSStdOut |
38  MythSystemLegacy ms(program, arguments, flags);
39  ms.SetDirectory(workingDirectory);
40  ms.Run();
41  if (ms.Wait() != GENERIC_EXIT_OK)
42  {
43  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
44  return types;
45  }
46 
47  QByteArray result = ms.ReadAll();
48  QTextStream text(result);
49 
50  while (!text.atEnd())
51  {
52  QString tmp = text.readLine();
53 
54  while (tmp.endsWith('\n') || tmp.endsWith('\r'))
55  tmp.chop(1);
56 
57  if (!tmp.isEmpty())
58  types += tmp;
59  }
60 
61  if (types.empty())
62  LOG(VB_GENERAL, LOG_ERR, loc + "Invalid output from -t option");
63 
64  return types;
65 }
66 
67 bool WeatherSource::ProbeTimeouts(const QString& workingDirectory,
68  const QString& program,
69  std::chrono::seconds &updateTimeout,
70  std::chrono::seconds &scriptTimeout)
71 {
72  QStringList arguments("-T");
73  const QString loc = QString("WeatherSource::ProbeTimeouts(%1 %2): ")
74  .arg(program, arguments.join(" "));
75 
77  scriptTimeout = DEFAULT_SCRIPT_TIMEOUT;
78 
79  uint flags = kMSRunShell | kMSStdOut |
81  MythSystemLegacy ms(program, arguments, flags);
82  ms.SetDirectory(workingDirectory);
83  ms.Run();
84  if (ms.Wait() != GENERIC_EXIT_OK)
85  {
86  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
87  return false;
88  }
89 
90  QByteArray result = ms.ReadAll();
91  QTextStream text(result);
92 
93  QStringList lines;
94  while (!text.atEnd())
95  {
96  QString tmp = text.readLine();
97 
98  while (tmp.endsWith('\n') || tmp.endsWith('\r'))
99  tmp.chop(1);
100 
101  if (!tmp.isEmpty())
102  lines << tmp;
103  }
104 
105  if (lines.empty())
106  {
107  LOG(VB_GENERAL, LOG_ERR, loc + "Invalid Script Output! No Lines");
108  return false;
109  }
110 
111  QStringList temp = lines[0].split(',');
112  if (temp.size() != 2)
113  {
114  LOG(VB_GENERAL, LOG_ERR, loc +
115  QString("Invalid Script Output! '%1'").arg(lines[0]));
116  return false;
117  }
118 
119  std::array<bool,2> isOK {};
120  uint ut = temp[0].toUInt(isOK.data());
121  uint st = temp[1].toUInt(&isOK[1]);
122  if (!isOK[0] || !isOK[1])
123  {
124  LOG(VB_GENERAL, LOG_ERR, loc +
125  QString("Invalid Script Output! '%1'").arg(lines[0]));
126  return false;
127  }
128 
129  updateTimeout = std::chrono::seconds(ut);
130  scriptTimeout = std::chrono::seconds(st);
131 
132  return true;
133 }
134 
136 {
137  QStringList arguments("-v");
138 
139  const QString loc = QString("WeatherSource::ProbeInfo(%1 %2): ")
140  .arg(info.program, arguments.join(" "));
141 
142  uint flags = kMSRunShell | kMSStdOut |
144  MythSystemLegacy ms(info.program, arguments, flags);
145  ms.SetDirectory(info.path);
146  ms.Run();
147  if (ms.Wait() != GENERIC_EXIT_OK)
148  {
149  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
150  return false;
151  }
152 
153  QByteArray result = ms.ReadAll();
154  QTextStream text(result);
155 
156  QStringList lines;
157  while (!text.atEnd())
158  {
159  QString tmp = text.readLine();
160 
161  while (tmp.endsWith('\n') || tmp.endsWith('\r'))
162  tmp.chop(1);
163 
164  if (!tmp.isEmpty())
165  lines << tmp;
166  }
167 
168  if (lines.empty())
169  {
170  LOG(VB_GENERAL, LOG_ERR, loc + "Invalid Script Output! No Lines");
171  return false;
172  }
173 
174  QStringList temp = lines[0].split(',');
175  if (temp.size() != 4)
176  {
177  LOG(VB_GENERAL, LOG_ERR, loc +
178  QString("Invalid Script Output! '%1'").arg(lines[0]));
179  return false;
180  }
181 
182  info.name = temp[0];
183  info.version = temp[1];
184  info.author = temp[2];
185  info.email = temp[3];
186 
187  return true;
188 }
189 
190 /* Basic logic of this behemouth...
191  * run script with -v flag, this returns among other things, the version number
192  * Search the database using the name (also returned from -v).
193  * if it exists, compare versions from -v and db
194  * if the same, populate the info struct from db, and we're done
195  * if they differ, get the rest of the needed information from the script and
196  * update the database, note, it does not overwrite the existing timeout values.
197  * if the script is not in the database, we probe it for types and default
198  * timeout values, and add it to the database
199  */
201 {
202  if (!fi.isReadable() || !fi.isExecutable())
203  return nullptr;
204 
206  info.path = fi.absolutePath();
207  info.program = fi.absoluteFilePath();
208 
210  return nullptr;
211 
213  QString query =
214  "SELECT sourceid, source_name, update_timeout, retrieve_timeout, "
215  "path, author, version, email, types FROM weathersourcesettings "
216  "WHERE hostname = :HOST AND source_name = :NAME;";
217  db.prepare(query);
218  db.bindValue(":HOST", gCoreContext->GetHostName());
219  db.bindValue(":NAME", info.name);
220 
221  if (!db.exec())
222  {
223  LOG(VB_GENERAL, LOG_ERR, "Invalid response from database");
224  return nullptr;
225  }
226 
227  // the script exists in the db
228  if (db.next())
229  {
230  info.id = db.value(0).toInt();
231  info.updateTimeout = std::chrono::seconds(db.value(2).toUInt());
232  info.scriptTimeout = std::chrono::seconds(db.value(3).toUInt());
233 
234  // compare versions, if equal... be happy
235  QString dbver = db.value(6).toString();
236  if (dbver == info.version)
237  {
238  info.types = db.value(8).toString().split(",");
239  }
240  else
241  {
242  // versions differ, change db to match script output
243  LOG(VB_GENERAL, LOG_INFO, "New version of " + info.name + " found");
244  query = "UPDATE weathersourcesettings SET source_name = :NAME, "
245  "path = :PATH, author = :AUTHOR, version = :VERSION, "
246  "email = :EMAIL, types = :TYPES WHERE sourceid = :ID";
247  db.prepare(query);
248  // these info values were populated when getting the version number
249  // we leave the timeout values in
250  db.bindValue(":NAME", info.name);
251  db.bindValue(":PATH", info.program);
252  db.bindValue(":AUTHOR", info.author);
253  db.bindValue(":VERSION", info.version);
254 
255  // run the script to get supported data types
256  info.types = WeatherSource::ProbeTypes(info.path, info.program);
257 
258  db.bindValue(":TYPES", info.types.join(","));
259  db.bindValue(":ID", info.id);
260  db.bindValue(":EMAIL", info.email);
261  if (!db.exec())
262  {
263  MythDB::DBError("Updating weather source settings.", db);
264  return nullptr;
265  }
266  }
267  }
268  else
269  {
270  // Script is not in db, probe it and insert it into db
271  query = "INSERT INTO weathersourcesettings "
272  "(hostname, source_name, update_timeout, retrieve_timeout, "
273  "path, author, version, email, types) "
274  "VALUES (:HOST, :NAME, :UPDATETO, :RETTO, :PATH, :AUTHOR, "
275  ":VERSION, :EMAIL, :TYPES);";
276 
278  info.program,
279  info.updateTimeout,
280  info.scriptTimeout))
281  {
282  return nullptr;
283  }
284  db.prepare(query);
285  db.bindValue(":NAME", info.name);
286  db.bindValue(":HOST", gCoreContext->GetHostName());
287  db.bindValue(":UPDATETO", QString::number(info.updateTimeout.count()));
288  db.bindValue(":RETTO", QString::number(info.scriptTimeout.count()));
289  db.bindValue(":PATH", info.program);
290  db.bindValue(":AUTHOR", info.author);
291  db.bindValue(":VERSION", info.version);
292  db.bindValue(":EMAIL", info.email);
293  info.types = ProbeTypes(info.path, info.program);
294  db.bindValue(":TYPES", info.types.join(","));
295  if (!db.exec())
296  {
297  MythDB::DBError("Inserting weather source", db);
298  return nullptr;
299  }
300  query = "SELECT sourceid FROM weathersourcesettings "
301  "WHERE source_name = :NAME AND hostname = :HOST;";
302  // a little annoying, but look at what we just inserted to get the id
303  // number, not sure if we really need it, but better safe than sorry.
304  db.prepare(query);
305  db.bindValue(":HOST", gCoreContext->GetHostName());
306  db.bindValue(":NAME", info.name);
307  if (!db.exec())
308  {
309  MythDB::DBError("Getting weather sourceid", db);
310  return nullptr;
311  }
312  if (!db.next())
313  {
314  LOG(VB_GENERAL, LOG_ERR, "Error getting weather sourceid");
315  return nullptr;
316  }
317  info.id = db.value(0).toInt();
318  }
319 
320  return new ScriptInfo(info);
321 }
322 
330  : m_ready(info != nullptr),
331  m_inuse(info != nullptr),
332  m_info(info),
333  m_updateTimer(new QTimer(this))
334 {
335  QDir dir(GetConfDir());
336  if (!dir.exists("MythWeather"))
337  dir.mkdir("MythWeather");
338  dir.cd("MythWeather");
339  if (info != nullptr) {
340  if (!dir.exists(info->name))
341  dir.mkdir(info->name);
342  dir.cd(info->name);
343  }
344  m_dir = dir.absolutePath();
345 
347 }
348 
350 {
351  if (m_ms)
352  {
354  m_ms->Wait(5s);
355  delete m_ms;
356  }
357  delete m_updateTimer;
358 }
359 
361 {
362  connect(this, &WeatherSource::newData,
364  ++m_connectCnt;
365 
366  if (!m_data.empty())
367  {
368  emit newData(m_locale, m_units, m_data);
369  }
370 }
371 
373 {
374  disconnect(this, nullptr, ws, nullptr);
375  --m_connectCnt;
376 }
377 
378 QStringList WeatherSource::getLocationList(const QString &str)
379 {
380  QString program = m_info->program;
381  QStringList args;
382  args << "-l";
383  args << str;
384 
385  const QString loc = QString("WeatherSource::getLocationList(%1 %2): ")
386  .arg(program, args.join(" "));
387 
388  uint flags = kMSRunShell | kMSStdOut |
390  MythSystemLegacy ms(program, args, flags);
391  ms.SetDirectory(m_info->path);
392  ms.Run();
393 
394  if (ms.Wait() != GENERIC_EXIT_OK)
395  {
396  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
397  return {};
398  }
399 
400  QStringList locs;
401  QByteArray result = ms.ReadAll();
402  QTextStream text(result);
403 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
404  text.setCodec("UTF-8");
405 #else
406  text.setEncoding(QStringConverter::Utf8);
407 #endif
408  while (!text.atEnd())
409  {
410  QString tmp = text.readLine().trimmed();
411  if (!tmp.isEmpty())
412  locs << tmp;
413  }
414 
415  return locs;
416 }
417 
418 void WeatherSource::startUpdate(bool forceUpdate)
419 {
420  m_buffer.clear();
421 
423  LOG(VB_GENERAL, LOG_INFO, "Starting update of " + m_info->name);
424 
425  if (m_ms)
426  {
427  LOG(VB_GENERAL, LOG_ERR, QString("%1 process exists, skipping.")
428  .arg(m_info->name));
429  return;
430  }
431 
432  if (!forceUpdate)
433  {
434  db.prepare("SELECT updated FROM weathersourcesettings "
435  "WHERE sourceid = :ID AND "
436  "TIMESTAMPADD(SECOND,update_timeout-15,updated) > NOW()");
437  db.bindValue(":ID", getId());
438  if (db.exec() && db.size() > 0)
439  {
440  LOG(VB_GENERAL, LOG_NOTICE, QString("%1 recently updated, skipping.")
441  .arg(m_info->name));
442 
443  if (m_cachefile.isEmpty())
444  {
445  QString locale_file(m_locale);
446  locale_file.replace("/", "-");
447  m_cachefile = QString("%1/cache_%2").arg(m_dir, locale_file);
448  }
449  QFile cache(m_cachefile);
450  if (cache.exists() && cache.open( QIODevice::ReadOnly ))
451  {
452  m_buffer = cache.readAll();
453  cache.close();
454 
455  processData();
456 
457  if (m_connectCnt)
458  {
459  emit newData(m_locale, m_units, m_data);
460  }
461  return;
462  }
463  LOG(VB_GENERAL, LOG_NOTICE,
464  QString("No cachefile for %1, forcing update.")
465  .arg(m_info->name));
466  }
467  }
468 
469  m_data.clear();
470  QString program = "nice";
471  QStringList args;
472  args << m_info->program;
473  args << "-u";
474  args << (m_units == SI_UNITS ? "SI" : "ENG");
475 
476  if (!m_dir.isEmpty())
477  {
478  args << "-d";
479  args << m_dir;
480  }
481  args << m_locale;
482 
485  m_ms = new MythSystemLegacy(program, args, flags);
487 
489  this, qOverload<>(&WeatherSource::processExit));
490  connect(m_ms, &MythSystemLegacy::error,
491  this, qOverload<uint>(&WeatherSource::processExit));
492 
494 }
495 
497 {
498  startUpdate();
500 }
501 
503 {
504  m_ms->disconnect(); // disconnects all signals
505 
506  if (status == GENERIC_EXIT_OK)
507  {
508  m_buffer = m_ms->ReadAll();
509  }
510 
511  delete m_ms;
512  m_ms = nullptr;
513 
514  if (status != GENERIC_EXIT_OK)
515  {
516  LOG(VB_GENERAL, LOG_ERR, QString("script exit status %1").arg(status));
517  return;
518  }
519 
520  if (m_buffer.isEmpty())
521  {
522  LOG(VB_GENERAL, LOG_ERR, "Script returned no data");
523  return;
524  }
525 
526  if (m_cachefile.isEmpty())
527  {
528  QString locale_file(m_locale);
529  locale_file.replace("/", "-");
530  m_cachefile = QString("%1/cache_%2").arg(m_dir, locale_file);
531  }
532  QFile cache(m_cachefile);
533  if (cache.open( QIODevice::WriteOnly ))
534  {
535  cache.write(m_buffer);
536  cache.close();
537  }
538  else
539  {
540  LOG(VB_GENERAL, LOG_ERR, QString("Unable to save data to cachefile: %1")
541  .arg(m_cachefile));
542  }
543 
544  processData();
545 
547 
548  db.prepare("UPDATE weathersourcesettings "
549  "SET updated = NOW() WHERE sourceid = :ID;");
550 
551  db.bindValue(":ID", getId());
552  if (!db.exec())
553  {
554  MythDB::DBError("Updating weather source's last update time", db);
555  return;
556  }
557 
558  if (m_connectCnt)
559  {
560  emit newData(m_locale, m_units, m_data);
561  }
562 }
563 
565 {
567 }
568 
570 {
571  QString unicode_buffer = QString::fromUtf8(m_buffer);
572  QStringList data = unicode_buffer.split('\n', Qt::SkipEmptyParts);
573 
574  m_data.clear();
575 
576  for (int i = 0; i < data.size(); ++i)
577  {
578  QStringList temp = data[i].split("::", Qt::SkipEmptyParts);
579  if (temp.size() > 2)
580  LOG(VB_GENERAL, LOG_ERR, "Error parsing script file, ignoring");
581  if (temp.size() < 2)
582  {
583  LOG(VB_GENERAL, LOG_ERR,
584  QString("Unrecoverable error parsing script output %1")
585  .arg(temp.size()));
586  LOG(VB_GENERAL, LOG_ERR, QString("data[%1]: '%2'")
587  .arg(i).arg(data[i]));
588  return; // we don't emit signal
589  }
590 
591  if (temp[1] != "---")
592  {
593  if (!m_data[temp[0]].isEmpty())
594  {
595  m_data[temp[0]].append("\n" + temp[1]);
596  }
597  else
598  {
599  m_data[temp[0]] = temp[1];
600  }
601  }
602  }
603 }
604 
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
WeatherSource::m_cachefile
QString m_cachefile
Definition: weatherSource.h:100
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
build_compdb.args
args
Definition: build_compdb.py:11
DEFAULT_SCRIPT_TIMEOUT
static constexpr std::chrono::seconds DEFAULT_SCRIPT_TIMEOUT
Definition: weatherUtils.h:21
WeatherSource::ProbeTypes
static QStringList ProbeTypes(const QString &workingDirectory, const QString &program)
Definition: weatherSource.cpp:28
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:214
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:101
kMSDontBlockInputDevs
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:36
mythdb.h
MythSystemLegacy
Definition: mythsystemlegacy.h:67
DEFAULT_UPDATE_TIMEOUT
static constexpr std::chrono::minutes DEFAULT_UPDATE_TIMEOUT
Definition: weatherUtils.h:20
ScriptInfo::program
QString program
Definition: weatherSource.h:29
WeatherSource::m_info
ScriptInfo * m_info
Definition: weatherSource.h:96
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
WeatherSource::m_ms
MythSystemLegacy * m_ms
Definition: weatherSource.h:97
MythSystemLegacy::finished
void finished(void)
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
WeatherSource::m_data
DataMap m_data
Definition: weatherSource.h:105
types
static const struct wl_interface * types[]
Definition: idle_inhibit_unstable_v1.c:39
WeatherSource::disconnectScreen
void disconnectScreen(WeatherScreen *ws)
Definition: weatherSource.cpp:372
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
WeatherSource::m_connectCnt
int m_connectCnt
Definition: weatherSource.h:104
MythSystemLegacy::ReadAll
QByteArray & ReadAll()
Definition: mythsystemlegacy.cpp:401
WeatherSource::startUpdateTimer
void startUpdateTimer()
Definition: weatherSource.h:72
mythdirs.h
weatherSource.h
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
mythsystemlegacy.h
WeatherSource::m_locale
QString m_locale
Definition: weatherSource.h:99
MythSystemLegacy::Signal
void Signal(MythSignal sig)
Definition: mythsystemlegacy.cpp:295
SI_UNITS
static constexpr uint8_t SI_UNITS
Definition: weatherUtils.h:18
WeatherScreen::newData
virtual void newData(const QString &, units_t, DataMap data)
Definition: weatherScreen.cpp:72
WeatherSource::ProbeInfo
static bool ProbeInfo(ScriptInfo &scriptInfo)
Definition: weatherSource.cpp:135
WeatherSource::processData
void processData()
Definition: weatherSource.cpp:569
mythlogging.h
WeatherSource::m_buffer
QByteArray m_buffer
Definition: weatherSource.h:101
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:263
WeatherSource::newData
void newData(QString, units_t, DataMap)
WeatherSource::processExit
void processExit()
Definition: weatherSource.cpp:564
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
MythSystemLegacy::error
void error(uint status)
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
compat.h
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
kSignalKill
@ kSignalKill
Definition: mythsystem.h:64
WeatherSource::updateTimeout
void updateTimeout()
Definition: weatherSource.cpp:496
MythSystemLegacy::Wait
uint Wait(std::chrono::seconds timeout=0s)
Definition: mythsystemlegacy.cpp:242
WeatherSource::ProbeTimeouts
static bool ProbeTimeouts(const QString &workingDirectory, const QString &program, std::chrono::seconds &updateTimeout, std::chrono::seconds &scriptTimeout)
Definition: weatherSource.cpp:67
WeatherSource::m_updateTimer
QTimer * m_updateTimer
Definition: weatherSource.h:103
MythSystemLegacy::SetDirectory
void SetDirectory(const QString &directory)
Definition: mythsystemlegacy.cpp:187
WeatherScreen
Weather screen.
Definition: weatherScreen.h:26
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
WeatherSource::WeatherSource
WeatherSource(ScriptInfo *info)
Watch out, we store the parameter as a member variable, don't go deleting it, that wouldn't be good.
Definition: weatherSource.cpp:329
kMSRunShell
@ kMSRunShell
run process through shell
Definition: mythsystem.h:43
WeatherSource::m_dir
QString m_dir
Definition: weatherSource.h:98
kMSRunBackground
@ kMSRunBackground
run child in the background
Definition: mythsystem.h:38
ScriptInfo::scriptTimeout
std::chrono::seconds scriptTimeout
Definition: weatherSource.h:31
mythcorecontext.h
WeatherSource::getId
int getId()
Definition: weatherSource.h:78
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
WeatherSource::m_units
units_t m_units
Definition: weatherSource.h:102
WeatherSource::startUpdate
void startUpdate(bool forceUpdate=false)
Definition: weatherSource.cpp:418
WeatherSource::connectScreen
void connectScreen(WeatherScreen *ws)
Definition: weatherSource.cpp:360
ScriptInfo::name
QString name
Definition: weatherSource.h:24
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:845
weatherScreen.h
WeatherSource::ProbeScript
static ScriptInfo * ProbeScript(const QFileInfo &fi)
Definition: weatherSource.cpp:200
azlyrics.info
dictionary info
Definition: azlyrics.py:7
MythSystemLegacy::Run
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
Definition: mythsystemlegacy.cpp:212
WeatherSource::~WeatherSource
~WeatherSource() override
Definition: weatherSource.cpp:349
kMSDontDisableDrawing
@ kMSDontDisableDrawing
avoid disabling UI drawing
Definition: mythsystem.h:37
ScriptInfo
Definition: serverSideScripting.h:35
exitcodes.h
kMSStdOut
@ kMSStdOut
allow access to stdout
Definition: mythsystem.h:41
ScriptInfo::path
QString path
Definition: weatherSource.h:30
uint
unsigned int uint
Definition: freesurround.h:24
WeatherSource::getLocationList
QStringList getLocationList(const QString &str)
Definition: weatherSource.cpp:378
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837