MythTV  master
httpstatus.cpp
Go to the documentation of this file.
1 // Program Name: httpstatus.cpp
3 //
4 // Purpose - Html & XML status HttpServerExtension
5 //
6 // Created By : David Blain Created On : Oct. 24, 2005
7 // Modified By : Modified On:
8 //
10 
11 // POSIX headers
12 #include <unistd.h>
13 
14 // ANSI C headers
15 #include <cmath>
16 #include <cstdio>
17 #include <cstdlib>
18 
19 // Qt headers
20 #include <QTextStream>
21 #include <QRegExp>
22 
23 // MythTV headers
24 #include "httpstatus.h"
25 
26 #include "mythcorecontext.h"
27 #include "mythversion.h"
28 #include "mythdbcon.h"
29 #include "compat.h"
30 #include "mythconfig.h"
31 #include "autoexpire.h"
32 #include "tv.h"
33 #include "encoderlink.h"
34 #include "scheduler.h"
35 #include "mainserver.h"
36 #include "cardutil.h"
37 #include "mythsystemlegacy.h"
38 #include "exitcodes.h"
39 #include "jobqueue.h"
40 #include "upnp.h"
41 #include "mythdate.h"
42 #include "tv_rec.h"
43 
45 //
47 
48 HttpStatus::HttpStatus( QMap<int, EncoderLink *> *tvList, Scheduler *sched,
49  AutoExpire *expirer, bool bIsMaster )
50  : HttpServerExtension( "HttpStatus" , QString())
51 {
53  m_pSched = sched;
55  m_bIsMaster = bIsMaster;
56 
57  m_nPreRollSeconds = gCoreContext->GetNumSetting("RecordPreRoll", 0);
58 
59  m_pMainServer = nullptr;
60 }
61 
63 //
65 
67 {
68  if (sURI == "Status" ) return( HSM_GetStatusHTML );
69  if (sURI == "GetStatusHTML" ) return( HSM_GetStatusHTML );
70  if (sURI == "GetStatus" ) return( HSM_GetStatusXML );
71  if (sURI == "xml" ) return( HSM_GetStatusXML );
72 
73  return( HSM_Unknown );
74 }
75 
77 //
79 
81 {
82  return QStringList( "/Status" );
83 }
84 
86 //
88 
90 {
91  try
92  {
93  if (pRequest)
94  {
95  if ((pRequest->m_sBaseUrl != "/Status" ) &&
96  (pRequest->m_sResourceUrl != "/Status" ))
97  {
98  return( false );
99  }
100 
101  switch( GetMethod( pRequest->m_sMethod ))
102  {
103  case HSM_GetStatusXML : GetStatusXML ( pRequest ); return true;
104  case HSM_GetStatusHTML : GetStatusHTML ( pRequest ); return true;
105 
106  default:
107  {
108  pRequest->m_eResponseType = ResponseTypeHTML;
109  pRequest->m_nResponseStatus = 200;
110 
111  break;
112  }
113  }
114  }
115  }
116  catch( ... )
117  {
118  LOG(VB_GENERAL, LOG_ERR,
119  "HttpStatus::ProcessRequest() - Unexpected Exception");
120  }
121 
122  return( false );
123 }
124 
126 //
128 
130 {
131  QDomDocument doc( "Status" );
132 
133  // UTF-8 is the default, but good practice to specify it anyway
134  QDomProcessingInstruction encoding =
135  doc.createProcessingInstruction("xml",
136  "version=\"1.0\" encoding=\"UTF-8\"");
137  doc.appendChild(encoding);
138 
139  FillStatusXML( &doc );
140 
141  pRequest->m_eResponseType = ResponseTypeXML;
142  pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
143 
144  QTextStream stream( &pRequest->m_response );
145  stream.setCodec("UTF-8"); // Otherwise locale default is used.
146  stream << doc.toString();
147 }
148 
150 //
152 
154 {
155  pRequest->m_eResponseType = ResponseTypeHTML;
156  pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
157 
158  QDomDocument doc( "Status" );
159 
160  FillStatusXML( &doc );
161 
162  QTextStream stream( &pRequest->m_response );
163  PrintStatus( stream, &doc );
164 }
165 
166 static QString setting_to_localtime(const char *setting)
167 {
168  QString origDateString = gCoreContext->GetSetting(setting);
169  QDateTime origDate = MythDate::fromString(origDateString);
171 }
172 
173 void HttpStatus::FillStatusXML( QDomDocument *pDoc )
174 {
175  QDateTime qdtNow = MythDate::current();
176 
177  // Add Root Node.
178 
179  QDomElement root = pDoc->createElement("Status");
180  pDoc->appendChild(root);
181 
182  root.setAttribute("date" , MythDate::toString(
184  root.setAttribute("time" ,
186  root.setAttribute("ISODate" , qdtNow.toString(Qt::ISODate) );
187  root.setAttribute("version" , MYTH_BINARY_VERSION );
188  root.setAttribute("protoVer", MYTH_PROTO_VERSION );
189 
190  // Add all encoders, if any
191 
192  QDomElement encoders = pDoc->createElement("Encoders");
193  root.appendChild(encoders);
194 
195  int numencoders = 0;
196  bool isLocal = true;
197 
198  TVRec::s_inputsLock.lockForRead();
199 
200  for (auto iter = m_pEncoders->begin(); iter != m_pEncoders->end(); ++iter)
201  {
202  EncoderLink *elink = *iter;
203 
204  if (elink != nullptr)
205  {
206  TVState state = elink->GetState();
207  isLocal = elink->IsLocal();
208 
209  QDomElement encoder = pDoc->createElement("Encoder");
210  encoders.appendChild(encoder);
211 
212  encoder.setAttribute("id" , elink->GetInputID() );
213  encoder.setAttribute("local" , static_cast<int>(isLocal));
214  encoder.setAttribute("connected" , static_cast<int>(elink->IsConnected()));
215  encoder.setAttribute("state" , state );
216  encoder.setAttribute("sleepstatus" , elink->GetSleepStatus() );
217  //encoder.setAttribute("lowOnFreeSpace", elink->isLowOnFreeSpace());
218 
219  if (isLocal)
220  encoder.setAttribute("hostname", gCoreContext->GetHostName());
221  else
222  encoder.setAttribute("hostname", elink->GetHostName());
223 
224  encoder.setAttribute("devlabel",
226 
227  if (elink->IsConnected())
228  numencoders++;
229 
230  switch (state)
231  {
235  {
236  ProgramInfo *pInfo = elink->GetRecording();
237 
238  if (pInfo)
239  {
240  FillProgramInfo(pDoc, encoder, pInfo);
241  delete pInfo;
242  }
243 
244  break;
245  }
246 
247  default:
248  break;
249  }
250  }
251  }
252 
253  TVRec::s_inputsLock.unlock();
254 
255  encoders.setAttribute("count", numencoders);
256 
257  // Add upcoming shows
258 
259  QDomElement scheduled = pDoc->createElement("Scheduled");
260  root.appendChild(scheduled);
261 
262  RecList recordingList;
263 
264  if (m_pSched)
265  m_pSched->GetAllPending(recordingList);
266 
267  unsigned int iNum = 10;
268  unsigned int iNumRecordings = 0;
269 
270  RecConstIter itProg = recordingList.begin();
271  for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg)
272  {
273  if (((*itProg)->GetRecordingStatus() <= RecStatus::WillRecord) &&
274  ((*itProg)->GetRecordingStartTime() >=
276  {
277  iNumRecordings++;
278  FillProgramInfo(pDoc, scheduled, *itProg);
279  }
280  }
281 
282  while (!recordingList.empty())
283  {
284  ProgramInfo *pginfo = recordingList.back();
285  delete pginfo;
286  recordingList.pop_back();
287  }
288 
289  scheduled.setAttribute("count", iNumRecordings);
290 
291  // Add known frontends
292 
293  QDomElement frontends = pDoc->createElement("Frontends");
294  root.appendChild(frontends);
295 
297  "urn:schemas-mythtv-org:service:MythFrontend:1");
298  if (fes)
299  {
300  EntryMap map;
301  fes->GetEntryMap(map);
302  fes->DecrRef();
303  fes = nullptr;
304 
305  frontends.setAttribute( "count", map.size() );
306  for (EntryMap::iterator it = map.begin(); it != map.end(); ++it)
307  {
308  QDomElement fe = pDoc->createElement("Frontend");
309  frontends.appendChild(fe);
310  QUrl url((*it)->m_sLocation);
311  fe.setAttribute("name", url.host());
312  fe.setAttribute("url", url.toString(QUrl::RemovePath));
313  (*it)->DecrRef();
314  }
315  }
316 
317  // Other backends
318 
319  QDomElement backends = pDoc->createElement("Backends");
320  root.appendChild(backends);
321 
322  int numbes = 0;
324  {
325  numbes++;
326  QString masterhost = gCoreContext->GetMasterHostName();
327  QString masterip = gCoreContext->GetMasterServerIP();
328  int masterport = gCoreContext->GetMasterServerStatusPort();
329 
330  QDomElement mbe = pDoc->createElement("Backend");
331  backends.appendChild(mbe);
332  mbe.setAttribute("type", "Master");
333  mbe.setAttribute("name", masterhost);
334  mbe.setAttribute("url" , masterip + ":" + masterport);
335  }
336 
338  "urn:schemas-mythtv-org:device:SlaveMediaServer:1");
339  if (sbes)
340  {
341 
342  QString ipaddress = QString();
343  if (!UPnp::g_IPAddrList.isEmpty())
344  ipaddress = UPnp::g_IPAddrList.at(0).toString();
345 
346  EntryMap map;
347  sbes->GetEntryMap(map);
348  sbes->DecrRef();
349  sbes = nullptr;
350 
351  for (EntryMap::iterator it = map.begin(); it != map.end(); ++it)
352  {
353  QUrl url((*it)->m_sLocation);
354  if (url.host() != ipaddress)
355  {
356  numbes++;
357  QDomElement mbe = pDoc->createElement("Backend");
358  backends.appendChild(mbe);
359  mbe.setAttribute("type", "Slave");
360  mbe.setAttribute("name", url.host());
361  mbe.setAttribute("url" , url.toString(QUrl::RemovePath));
362  }
363  (*it)->DecrRef();
364  }
365  }
366 
367  backends.setAttribute("count", numbes);
368 
369  // Add Job Queue Entries
370 
371  QDomElement jobqueue = pDoc->createElement("JobQueue");
372  root.appendChild(jobqueue);
373 
374  QMap<int, JobQueueEntry> jobs;
375  QMap<int, JobQueueEntry>::Iterator it;
376 
380 
381  for (it = jobs.begin(); it != jobs.end(); ++it)
382  {
383  ProgramInfo pginfo((*it).chanid, (*it).recstartts);
384  if (!pginfo.GetChanID())
385  continue;
386 
387  QDomElement job = pDoc->createElement("Job");
388  jobqueue.appendChild(job);
389 
390  job.setAttribute("id" , (*it).id );
391  job.setAttribute("chanId" , (*it).chanid );
392  job.setAttribute("startTime" ,
393  (*it).recstartts.toString(Qt::ISODate));
394  job.setAttribute("startTs" , (*it).startts );
395  job.setAttribute("insertTime",
396  (*it).inserttime.toString(Qt::ISODate));
397  job.setAttribute("type" , (*it).type );
398  job.setAttribute("cmds" , (*it).cmds );
399  job.setAttribute("flags" , (*it).flags );
400  job.setAttribute("status" , (*it).status );
401  job.setAttribute("statusTime",
402  (*it).statustime.toString(Qt::ISODate));
403  job.setAttribute("schedTime" ,
404  (*it).schedruntime.toString(Qt::ISODate));
405  job.setAttribute("args" , (*it).args );
406 
407  if ((*it).hostname.isEmpty())
408  job.setAttribute("hostname", QObject::tr("master"));
409  else
410  job.setAttribute("hostname",(*it).hostname);
411 
412  QDomText textNode = pDoc->createTextNode((*it).comment);
413  job.appendChild(textNode);
414 
415  FillProgramInfo(pDoc, job, &pginfo);
416  }
417 
418  jobqueue.setAttribute( "count", jobs.size() );
419 
420  // Add Machine information
421 
422  QDomElement mInfo = pDoc->createElement("MachineInfo");
423  QDomElement storage = pDoc->createElement("Storage" );
424  QDomElement load = pDoc->createElement("Load" );
425  QDomElement guide = pDoc->createElement("Guide" );
426 
427  root.appendChild (mInfo );
428  mInfo.appendChild(storage);
429  mInfo.appendChild(load );
430  mInfo.appendChild(guide );
431 
432  // drive space ---------------------
433 
434  QStringList strlist;
435  QString dirs;
436  QString hostname;
437  QString directory;
438  QString isLocalstr;
439  QString fsID;
440  QString ids;
441 
442  if (m_pMainServer)
444 
445  QDomElement total;
446 
447  // Make a temporary list to hold the per-filesystem elements so that the
448  // total is always the first element.
449  QList<QDomElement> fsXML;
450  QStringList::const_iterator sit = strlist.begin();
451  while (sit != strlist.end())
452  {
453  // cppcheck-suppress unreadVariable
454  hostname = *(sit++);
455  directory = *(sit++);
456  // cppcheck-suppress unreadVariable
457  isLocalstr = *(sit++);
458  fsID = *(sit++);
459  ++sit; // ignore dirID
460  ++sit; // ignore blocksize
461  long long iTotal = (*(sit++)).toLongLong();
462  long long iUsed = (*(sit++)).toLongLong();;
463  long long iAvail = iTotal - iUsed;
464 
465  if (fsID == "-2")
466  fsID = "total";
467 
468  QDomElement group = pDoc->createElement("Group");
469 
470  group.setAttribute("id" , fsID );
471  group.setAttribute("total", (int)(iTotal>>10) );
472  group.setAttribute("used" , (int)(iUsed>>10) );
473  group.setAttribute("free" , (int)(iAvail>>10) );
474  group.setAttribute("dir" , directory );
475 
476  if (fsID == "total")
477  {
478  long long iLiveTV = -1, iDeleted = -1, iExpirable = -1;
479  MSqlQuery query(MSqlQuery::InitCon());
480  query.prepare("SELECT SUM(filesize) FROM recorded "
481  " WHERE recgroup = :RECGROUP;");
482 
483  query.bindValue(":RECGROUP", "LiveTV");
484  if (query.exec() && query.next())
485  {
486  iLiveTV = query.value(0).toLongLong();
487  }
488  query.bindValue(":RECGROUP", "Deleted");
489  if (query.exec() && query.next())
490  {
491  iDeleted = query.value(0).toLongLong();
492  }
493  query.prepare("SELECT SUM(filesize) FROM recorded "
494  " WHERE autoexpire = 1 "
495  " AND recgroup NOT IN ('LiveTV', 'Deleted');");
496  if (query.exec() && query.next())
497  {
498  iExpirable = query.value(0).toLongLong();
499  }
500  group.setAttribute("livetv", (int)(iLiveTV>>20) );
501  group.setAttribute("deleted", (int)(iDeleted>>20) );
502  group.setAttribute("expirable", (int)(iExpirable>>20) );
503  total = group;
504  }
505  else
506  fsXML << group;
507  }
508 
509  storage.appendChild(total);
510  int num_elements = fsXML.size();
511  for (int fs_index = 0; fs_index < num_elements; fs_index++)
512  {
513  storage.appendChild(fsXML[fs_index]);
514  }
515 
516  // load average ---------------------
517 
518 #ifdef Q_OS_ANDROID
519  load.setAttribute("avg1", 0);
520  load.setAttribute("avg2", 1);
521  load.setAttribute("avg3", 2);
522 #else
523  double rgdAverages[3];
524 
525  if (getloadavg(rgdAverages, 3) != -1)
526  {
527  load.setAttribute("avg1", rgdAverages[0]);
528  load.setAttribute("avg2", rgdAverages[1]);
529  load.setAttribute("avg3", rgdAverages[2]);
530  }
531 #endif
532 
533  // Guide Data ---------------------
534 
535  QDateTime GuideDataThrough;
536 
537  MSqlQuery query(MSqlQuery::InitCon());
538  query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;");
539 
540  if (query.exec() && query.next())
541  {
542  GuideDataThrough = MythDate::fromString(query.value(0).toString());
543  }
544 
545  guide.setAttribute("start",
546  setting_to_localtime("mythfilldatabaseLastRunStart"));
547  guide.setAttribute("end",
548  setting_to_localtime("mythfilldatabaseLastRunEnd"));
549  guide.setAttribute("status",
550  gCoreContext->GetSetting("mythfilldatabaseLastRunStatus"));
551  if (gCoreContext->GetBoolSetting("MythFillGrabberSuggestsTime", false))
552  {
553  guide.setAttribute("next",
554  gCoreContext->GetSetting("MythFillSuggestedRunTime"));
555  }
556 
557  if (!GuideDataThrough.isNull())
558  {
559  guide.setAttribute("guideThru",
560  GuideDataThrough.toString(Qt::ISODate));
561  guide.setAttribute("guideDays", qdtNow.daysTo(GuideDataThrough));
562  }
563 
564  // Add Miscellaneous information
565 
566  QString info_script = gCoreContext->GetSetting("MiscStatusScript");
567  if ((!info_script.isEmpty()) && (info_script != "none"))
568  {
569  QDomElement misc = pDoc->createElement("Miscellaneous");
570  root.appendChild(misc);
571 
572  uint flags = kMSRunShell | kMSStdOut;
573  MythSystemLegacy ms(info_script, flags);
574  ms.Run(10);
575  if (ms.Wait() != GENERIC_EXIT_OK)
576  {
577  LOG(VB_GENERAL, LOG_ERR,
578  QString("Error running miscellaneous "
579  "status information script: %1").arg(info_script));
580  return;
581  }
582 
583  QByteArray input = ms.ReadAll();
584 
585  QStringList output = QString(input).split('\n',
586  QString::SkipEmptyParts);
587 
588  for (auto iter = output.begin(); iter != output.end(); ++iter)
589  {
590  QDomElement info = pDoc->createElement("Information");
591 
592  QStringList list = (*iter).split("[]:[]");
593  unsigned int size = list.size();
594  unsigned int hasAttributes = 0;
595 
596  if ((size > 0) && (!list[0].isEmpty()))
597  {
598  info.setAttribute("display", list[0]);
599  hasAttributes++;
600  }
601  if ((size > 1) && (!list[1].isEmpty()))
602  {
603  info.setAttribute("name", list[1]);
604  hasAttributes++;
605  }
606  if ((size > 2) && (!list[2].isEmpty()))
607  {
608  info.setAttribute("value", list[2]);
609  hasAttributes++;
610  }
611 
612  if (hasAttributes > 0)
613  misc.appendChild(info);
614  }
615  }
616 }
617 
619 //
621 
622 void HttpStatus::PrintStatus( QTextStream &os, QDomDocument *pDoc )
623 {
624  os.setCodec("UTF-8");
625 
626  QDateTime qdtNow = MythDate::current();
627 
628  QDomElement docElem = pDoc->documentElement();
629 
630  os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
631  << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
632  << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
633  << " xml:lang=\"en\" lang=\"en\">\r\n"
634  << "<head>\r\n"
635  << " <meta http-equiv=\"Content-Type\""
636  << "content=\"text/html; charset=UTF-8\" />\r\n"
637  << " <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
638  << " <title>MythTV Status - "
639  << docElem.attribute( "date", MythDate::toString(qdtNow, MythDate::kDateShort) )
640  << " "
641  << docElem.attribute( "time", MythDate::toString(qdtNow, MythDate::kTime) ) << " - "
642  << docElem.attribute( "version", MYTH_BINARY_VERSION ) << "</title>\r\n"
643  << "</head>\r\n"
644  << "<body bgcolor=\"#fff\">\r\n"
645  << "<div class=\"status\">\r\n"
646  << " <h1 class=\"status\">MythTV Status</h1>\r\n";
647 
648  // encoder information ---------------------
649 
650  QDomNode node = docElem.namedItem( "Encoders" );
651 
652  if (!node.isNull())
653  PrintEncoderStatus( os, node.toElement() );
654 
655  // upcoming shows --------------------------
656 
657  node = docElem.namedItem( "Scheduled" );
658 
659  if (!node.isNull())
660  PrintScheduled( os, node.toElement());
661 
662  // Frontends
663 
664  node = docElem.namedItem( "Frontends" );
665 
666  if (!node.isNull())
667  PrintFrontends (os, node.toElement());
668 
669  // Backends
670 
671  node = docElem.namedItem( "Backends" );
672 
673  if (!node.isNull())
674  PrintBackends (os, node.toElement());
675 
676  // Job Queue Entries -----------------------
677 
678  node = docElem.namedItem( "JobQueue" );
679 
680  if (!node.isNull())
681  PrintJobQueue( os, node.toElement());
682 
683  // Machine information ---------------------
684 
685  node = docElem.namedItem( "MachineInfo" );
686 
687  if (!node.isNull())
688  PrintMachineInfo( os, node.toElement());
689 
690  // Miscellaneous information ---------------
691 
692  node = docElem.namedItem( "Miscellaneous" );
693 
694  if (!node.isNull())
695  PrintMiscellaneousInfo( os, node.toElement());
696 
697  os << "\r\n</div>\r\n</body>\r\n</html>\r\n";
698 
699 }
700 
702 //
704 
705 int HttpStatus::PrintEncoderStatus( QTextStream &os, const QDomElement& encoders )
706 {
707  int nNumEncoders = 0;
708 
709  if (encoders.isNull())
710  return 0;
711 
712  os << " <div class=\"content\">\r\n"
713  << " <h2 class=\"status\">Encoder Status</h2>\r\n";
714 
715  QDomNode node = encoders.firstChild();
716 
717  while (!node.isNull())
718  {
719  QDomElement e = node.toElement();
720 
721  if (!e.isNull())
722  {
723  if (e.tagName() == "Encoder")
724  {
725  QString sIsLocal = (e.attribute( "local" , "remote" )== "1")
726  ? "local" : "remote";
727  QString sCardId = e.attribute( "id" , "0" );
728  QString sHostName = e.attribute( "hostname" , "Unknown");
729  bool bConnected= static_cast<bool>(e.attribute( "connected", "0" ).toInt());
730 
731  bool bIsLowOnFreeSpace=static_cast<bool>(e.attribute( "lowOnFreeSpace", "0").toInt());
732 
733  QString sDevlabel = e.attribute( "devlabel", "[ UNKNOWN ]");
734 
735  os << " Encoder " << sCardId << " " << sDevlabel
736  << " is " << sIsLocal << " on " << sHostName;
737 
738  if ((sIsLocal == "remote") && !bConnected)
739  {
740  SleepStatus sleepStatus =
741  (SleepStatus) e.attribute("sleepstatus",
742  QString((int)sStatus_Undefined)).toInt();
743 
744  if (sleepStatus == sStatus_Asleep)
745  os << " (currently asleep).<br />";
746  else
747  os << " (currently not connected).<br />";
748 
749  node = node.nextSibling();
750  continue;
751  }
752 
753  nNumEncoders++;
754 
755  TVState encState = (TVState) e.attribute( "state", "0").toInt();
756 
757  switch( encState )
758  {
760  os << " and is watching Live TV";
761  break;
762 
765  os << " and is recording";
766  break;
767 
768  default:
769  os << " and is not recording.";
770  break;
771  }
772 
773  // Display first Program Element listed under the encoder
774 
775  QDomNode tmpNode = e.namedItem( "Program" );
776 
777  if (!tmpNode.isNull())
778  {
779  QDomElement program = tmpNode.toElement();
780 
781  if (!program.isNull())
782  {
783  os << " '" << program.attribute( "title", "Unknown" ) << "'";
784 
785  // Get Channel information
786 
787  tmpNode = program.namedItem( "Channel" );
788 
789  if (!tmpNode.isNull())
790  {
791  QDomElement channel = tmpNode.toElement();
792 
793  if (!channel.isNull())
794  os << " on "
795  << channel.attribute( "callSign", "unknown" );
796  }
797 
798  // Get Recording Information (if any)
799 
800  tmpNode = program.namedItem( "Recording" );
801 
802  if (!tmpNode.isNull())
803  {
804  QDomElement recording = tmpNode.toElement();
805 
806  if (!recording.isNull())
807  {
808  QDateTime endTs = MythDate::fromString(
809  recording.attribute( "recEndTs", "" ));
810 
811  os << ". This recording ";
812  if (endTs < MythDate::current())
813  os << "was ";
814  else
815  os << "is ";
816 
817  os << "scheduled to end at "
818  << MythDate::toString(endTs,
820  }
821  }
822  }
823 
824  os << ".";
825  }
826 
827  if (bIsLowOnFreeSpace)
828  {
829  os << " <strong>WARNING</strong>:"
830  << " This backend is low on free disk space!";
831  }
832 
833  os << "<br />\r\n";
834  }
835  }
836 
837  node = node.nextSibling();
838  }
839 
840  os << " </div>\r\n\r\n";
841 
842  return( nNumEncoders );
843 }
844 
846 //
848 
849 int HttpStatus::PrintScheduled( QTextStream &os, const QDomElement& scheduled )
850 {
851  QDateTime qdtNow = MythDate::current();
852 
853  if (scheduled.isNull())
854  return( 0 );
855 
856  int nNumRecordings= scheduled.attribute( "count", "0" ).toInt();
857 
858  os << " <div class=\"content\">\r\n"
859  << " <h2 class=\"status\">Schedule</h2>\r\n";
860 
861  if (nNumRecordings == 0)
862  {
863  os << " There are no shows scheduled for recording.\r\n"
864  << " </div>\r\n";
865  return( 0 );
866  }
867 
868  os << " The next " << nNumRecordings << " show" << (nNumRecordings == 1 ? "" : "s" )
869  << " that " << (nNumRecordings == 1 ? "is" : "are")
870  << " scheduled for recording:\r\n";
871 
872  os << " <div class=\"schedule\">\r\n";
873 
874  // Iterate through all scheduled programs
875 
876  QDomNode node = scheduled.firstChild();
877 
878  while (!node.isNull())
879  {
880  QDomElement e = node.toElement();
881 
882  if (!e.isNull())
883  {
884  QDomNode recNode = e.namedItem( "Recording" );
885  QDomNode chanNode = e.namedItem( "Channel" );
886 
887  if ((e.tagName() == "Program") && !recNode.isNull() &&
888  !chanNode.isNull())
889  {
890  QDomElement r = recNode.toElement();
891  QDomElement c = chanNode.toElement();
892 
893  QString sTitle = e.attribute( "title" , "" );
894  QString sSubTitle = e.attribute( "subTitle", "" );
895  QDateTime airDate = MythDate::fromString( e.attribute( "airdate" ,"" ));
896  QDateTime startTs = MythDate::fromString( e.attribute( "startTime" ,"" ));
897  QDateTime endTs = MythDate::fromString( e.attribute( "endTime" ,"" ));
898  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
899 // QDateTime recEndTs = MythDate::fromString( r.attribute( "recEndTs" ,"" ));
900  int nPreRollSecs = r.attribute( "preRollSeconds", "0" ).toInt();
901  int nEncoderId = r.attribute( "encoderId" , "0" ).toInt();
902  QString sProfile = r.attribute( "recProfile" , "" );
903  QString sChanName = c.attribute( "channelName" , "" );
904  QString sDesc = "";
905 
906  QDomText text = e.firstChild().toText();
907  if (!text.isNull())
908  sDesc = text.nodeValue();
909 
910  // Build Time to recording start.
911 
912  int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
913 
914  //since we're not displaying seconds
915 
916  nTotalSecs -= 60;
917 
918  int nTotalDays = nTotalSecs / 86400;
919  int nTotalHours = (nTotalSecs / 3600)
920  - (nTotalDays * 24);
921  int nTotalMins = (nTotalSecs / 60) % 60;
922 
923  QString sTimeToStart = "in";
924 
925  sTimeToStart += QObject::tr(" %n day(s),", "", nTotalDays );
926  sTimeToStart += QObject::tr(" %n hour(s) and", "", nTotalHours);
927  sTimeToStart += QObject::tr(" %n minute(s)", "", nTotalMins);
928 
929  if ( nTotalHours == 0 && nTotalMins == 0)
930  sTimeToStart = QObject::tr("within one minute", "Recording starting");
931 
932  if ( nTotalSecs < 0)
933  sTimeToStart = QObject::tr("soon", "Recording starting");
934 
935  // Output HTML
936 
937  os << " <a href=\"#\">";
938  os << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
940  MythDate::kSimplify) << " "
941  << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
942  MythDate::kTime) << " - ";
943 
944  if (nEncoderId > 0)
945  os << "Encoder " << nEncoderId << " - ";
946 
947  os << sChanName << " - " << sTitle << "<br />"
948  << "<span><strong>" << sTitle << "</strong> ("
949  << MythDate::toString(startTs, MythDate::kTime) << "-"
950  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
951 
952  if ( !sSubTitle.isEmpty())
953  os << "<em>" << sSubTitle << "</em><br /><br />";
954 
955  if ( airDate.isValid())
956  os << "Orig. Airdate: "
959  << "<br /><br />";
960 
961  os << sDesc << "<br /><br />"
962  << "This recording will start " << sTimeToStart
963  << " using encoder " << nEncoderId << " with the '"
964  << sProfile << "' profile.</span></a><hr />\r\n";
965  }
966  }
967 
968  node = node.nextSibling();
969  }
970  os << " </div>\r\n";
971  os << " </div>\r\n\r\n";
972 
973  return( nNumRecordings );
974 }
975 
977 //
979 
980 int HttpStatus::PrintFrontends( QTextStream &os, const QDomElement& frontends )
981 {
982  if (frontends.isNull())
983  return( 0 );
984 
985  int nNumFES= frontends.attribute( "count", "0" ).toInt();
986 
987  if (nNumFES < 1)
988  return( 0 );
989 
990 
991  os << " <div class=\"content\">\r\n"
992  << " <h2 class=\"status\">Frontends</h2>\r\n";
993 
994  QDomNode node = frontends.firstChild();
995  while (!node.isNull())
996  {
997  QDomElement e = node.toElement();
998 
999  if (!e.isNull())
1000  {
1001  QString name = e.attribute( "name" , "" );
1002  QString url = e.attribute( "url" , "" );
1003  os << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1004  }
1005 
1006  node = node.nextSibling();
1007  }
1008 
1009  os << " </div>\r\n\r\n";
1010 
1011  return nNumFES;
1012 }
1013 
1015 //
1017 
1018 int HttpStatus::PrintBackends( QTextStream &os, const QDomElement& backends )
1019 {
1020  if (backends.isNull())
1021  return( 0 );
1022 
1023  int nNumBES= backends.attribute( "count", "0" ).toInt();
1024 
1025  if (nNumBES < 1)
1026  return( 0 );
1027 
1028 
1029  os << " <div class=\"content\">\r\n"
1030  << " <h2 class=\"status\">Other Backends</h2>\r\n";
1031 
1032  QDomNode node = backends.firstChild();
1033  while (!node.isNull())
1034  {
1035  QDomElement e = node.toElement();
1036 
1037  if (!e.isNull())
1038  {
1039  QString type = e.attribute( "type", "" );
1040  QString name = e.attribute( "name" , "" );
1041  QString url = e.attribute( "url" , "" );
1042  os << type << ": " << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1043  }
1044 
1045  node = node.nextSibling();
1046  }
1047 
1048  os << " </div>\r\n\r\n";
1049 
1050  return nNumBES;
1051 }
1052 
1054 //
1056 
1057 int HttpStatus::PrintJobQueue( QTextStream &os, const QDomElement& jobs )
1058 {
1059  if (jobs.isNull())
1060  return( 0 );
1061 
1062  int nNumJobs= jobs.attribute( "count", "0" ).toInt();
1063 
1064  os << " <div class=\"content\">\r\n"
1065  << " <h2 class=\"status\">Job Queue</h2>\r\n";
1066 
1067  if (nNumJobs != 0)
1068  {
1069  QString statusColor;
1070  QString jobColor;
1071 
1072  os << " Jobs currently in Queue or recently ended:\r\n<br />"
1073  << " <div class=\"schedule\">\r\n";
1074 
1075 
1076  QDomNode node = jobs.firstChild();
1077 
1078  while (!node.isNull())
1079  {
1080  QDomElement e = node.toElement();
1081 
1082  if (!e.isNull())
1083  {
1084  QDomNode progNode = e.namedItem( "Program" );
1085 
1086  if ((e.tagName() == "Job") && !progNode.isNull() )
1087  {
1088  QDomElement p = progNode.toElement();
1089 
1090  QDomNode recNode = p.namedItem( "Recording" );
1091  QDomNode chanNode = p.namedItem( "Channel" );
1092 
1093  QDomElement r = recNode.toElement();
1094  QDomElement c = chanNode.toElement();
1095 
1096  int nType = e.attribute( "type" , "0" ).toInt();
1097  int nStatus = e.attribute( "status", "0" ).toInt();
1098 
1099  switch( nStatus )
1100  {
1101  case JOB_ABORTED:
1102  statusColor = " class=\"jobaborted\"";
1103  jobColor = "";
1104  break;
1105 
1106  case JOB_ERRORED:
1107  statusColor = " class=\"joberrored\"";
1108  jobColor = " class=\"joberrored\"";
1109  break;
1110 
1111  case JOB_FINISHED:
1112  statusColor = " class=\"jobfinished\"";
1113  jobColor = " class=\"jobfinished\"";
1114  break;
1115 
1116  case JOB_RUNNING:
1117  statusColor = " class=\"jobrunning\"";
1118  jobColor = " class=\"jobrunning\"";
1119  break;
1120 
1121  default:
1122  statusColor = " class=\"jobqueued\"";
1123  jobColor = " class=\"jobqueued\"";
1124  break;
1125  }
1126 
1127  QString sTitle = p.attribute( "title" , "" ); //.replace(QRegExp("\""), "&quot;");
1128  QString sSubTitle = p.attribute( "subTitle", "" );
1129  QDateTime startTs = MythDate::fromString( p.attribute( "startTime" ,"" ));
1130  QDateTime endTs = MythDate::fromString( p.attribute( "endTime" ,"" ));
1131  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
1132  QDateTime statusTime = MythDate::fromString( e.attribute( "statusTime","" ));
1133  QDateTime schedRunTime = MythDate::fromString( e.attribute( "schedTime","" ));
1134  QString sHostname = e.attribute( "hostname", "master" );
1135  QString sComment = "";
1136 
1137  QDomText text = e.firstChild().toText();
1138  if (!text.isNull())
1139  sComment = text.nodeValue();
1140 
1141  os << "<a href=\"javascript:void(0)\">"
1142  << MythDate::toString(recStartTs, MythDate::kDateFull |
1144  << " - "
1145  << sTitle << " - <font" << jobColor << ">"
1146  << JobQueue::JobText( nType ) << "</font><br />"
1147  << "<span><strong>" << sTitle << "</strong> ("
1148  << MythDate::toString(startTs, MythDate::kTime) << "-"
1149  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
1150 
1151  if (!sSubTitle.isEmpty())
1152  os << "<em>" << sSubTitle << "</em><br /><br />";
1153 
1154  os << "Job: " << JobQueue::JobText( nType ) << "<br />";
1155 
1156  if (schedRunTime > MythDate::current())
1157  os << "Scheduled Run Time: "
1158  << MythDate::toString(schedRunTime,
1161  << "<br />";
1162 
1163  os << "Status: <font" << statusColor << ">"
1164  << JobQueue::StatusText( nStatus )
1165  << "</font><br />"
1166  << "Status Time: "
1167  << MythDate::toString(statusTime, MythDate::kDateFull |
1169  << "<br />";
1170 
1171  if ( nStatus != JOB_QUEUED)
1172  os << "Host: " << sHostname << "<br />";
1173 
1174  if (!sComment.isEmpty())
1175  os << "<br />Comments:<br />" << sComment << "<br />";
1176 
1177  os << "</span></a><hr />\r\n";
1178  }
1179  }
1180 
1181  node = node.nextSibling();
1182  }
1183  os << " </div>\r\n";
1184  }
1185  else
1186  os << " Job Queue is currently empty.\r\n\r\n";
1187 
1188  os << " </div>\r\n\r\n ";
1189 
1190  return( nNumJobs );
1191 
1192 }
1193 
1195 //
1197 
1198 int HttpStatus::PrintMachineInfo( QTextStream &os, const QDomElement& info )
1199 {
1200  QString sRep;
1201 
1202  if (info.isNull())
1203  return( 0 );
1204 
1205  os << "<div class=\"content\">\r\n"
1206  << " <h2 class=\"status\">Machine Information</h2>\r\n";
1207 
1208  // load average ---------------------
1209 
1210  QDomNode node = info.namedItem( "Load" );
1211 
1212  if (!node.isNull())
1213  {
1214  QDomElement e = node.toElement();
1215 
1216  if (!e.isNull())
1217  {
1218  double dAvg1 = e.attribute( "avg1" , "0" ).toDouble();
1219  double dAvg2 = e.attribute( "avg2" , "0" ).toDouble();
1220  double dAvg3 = e.attribute( "avg3" , "0" ).toDouble();
1221 
1222  os << " <div class=\"loadstatus\">\r\n"
1223  << " This machine's load average:"
1224  << "\r\n <ul>\r\n <li>"
1225  << "1 Minute: " << dAvg1 << "</li>\r\n"
1226  << " <li>5 Minutes: " << dAvg2 << "</li>\r\n"
1227  << " <li>15 Minutes: " << dAvg3
1228  << "</li>\r\n </ul>\r\n"
1229  << " </div>\r\n";
1230  }
1231  }
1232 
1233  // local drive space ---------------------
1234  node = info.namedItem( "Storage" );
1235  QDomElement storage = node.toElement();
1236  node = storage.firstChild();
1237 
1238  // Loop once until we find id == "total". This should be first, but a loop
1239  // separate from the per-filesystem details loop ensures total is first,
1240  // regardless.
1241  while (!node.isNull())
1242  {
1243  QDomElement g = node.toElement();
1244 
1245  if (!g.isNull() && g.tagName() == "Group")
1246  {
1247  QString id = g.attribute("id", "" );
1248 
1249  if (id == "total")
1250  {
1251  int nFree = g.attribute("free" , "0" ).toInt();
1252  int nTotal = g.attribute("total", "0" ).toInt();
1253  int nUsed = g.attribute("used" , "0" ).toInt();
1254  int nLiveTV = g.attribute("livetv" , "0" ).toInt();
1255  int nDeleted = g.attribute("deleted", "0" ).toInt();
1256  int nExpirable = g.attribute("expirable" , "0" ).toInt();
1257  QString nDir = g.attribute("dir" , "" );
1258 
1259  nDir.replace(QRegExp(","), ", ");
1260 
1261  os << " Disk Usage Summary:<br />\r\n";
1262  os << " <ul>\r\n";
1263 
1264  os << " <li>Total Disk Space:\r\n"
1265  << " <ul>\r\n";
1266 
1267  os << " <li>Total Space: ";
1268  sRep = QString("%L1").arg(nTotal) + " MB";
1269  os << sRep << "</li>\r\n";
1270 
1271  os << " <li>Space Used: ";
1272  sRep = QString("%L1").arg(nUsed) + " MB";
1273  os << sRep << "</li>\r\n";
1274 
1275  os << " <li>Space Free: ";
1276  sRep = QString("%L1").arg(nFree) + " MB";
1277  os << sRep << "</li>\r\n";
1278 
1279  if ((nLiveTV + nDeleted + nExpirable) > 0)
1280  {
1281  os << " <li>Space Available "
1282  "After Auto-expire: ";
1283  sRep = QString("%L1").arg(nUsed) + " MB";
1284  sRep = QString("%L1").arg(nFree + nLiveTV +
1285  nDeleted + nExpirable) + " MB";
1286  os << sRep << "\r\n";
1287  os << " <ul>\r\n";
1288  os << " <li>Space Used by LiveTV: ";
1289  sRep = QString("%L1").arg(nLiveTV) + " MB";
1290  os << sRep << "</li>\r\n";
1291  os << " <li>Space Used by "
1292  "Deleted Recordings: ";
1293  sRep = QString("%L1").arg(nDeleted) + " MB";
1294  os << sRep << "</li>\r\n";
1295  os << " <li>Space Used by "
1296  "Auto-expirable Recordings: ";
1297  sRep = QString("%L1").arg(nExpirable) + " MB";
1298  os << sRep << "</li>\r\n";
1299  os << " </ul>\r\n";
1300  os << " </li>\r\n";
1301  }
1302 
1303  os << " </ul>\r\n"
1304  << " </li>\r\n";
1305 
1306  os << " </ul>\r\n";
1307  break;
1308  }
1309  }
1310 
1311  node = node.nextSibling();
1312  }
1313 
1314  // Loop again to handle per-filesystem details.
1315  node = storage.firstChild();
1316 
1317  os << " Disk Usage Details:<br />\r\n";
1318  os << " <ul>\r\n";
1319 
1320 
1321  while (!node.isNull())
1322  {
1323  QDomElement g = node.toElement();
1324 
1325  if (!g.isNull() && g.tagName() == "Group")
1326  {
1327  int nFree = g.attribute("free" , "0" ).toInt();
1328  int nTotal = g.attribute("total", "0" ).toInt();
1329  int nUsed = g.attribute("used" , "0" ).toInt();
1330  QString nDir = g.attribute("dir" , "" );
1331  QString id = g.attribute("id" , "" );
1332 
1333  nDir.replace(QRegExp(","), ", ");
1334 
1335 
1336  if (id != "total")
1337  {
1338 
1339  os << " <li>MythTV Drive #" << id << ":"
1340  << "\r\n"
1341  << " <ul>\r\n";
1342 
1343  if (nDir.contains(','))
1344  os << " <li>Directories: ";
1345  else
1346  os << " <li>Directory: ";
1347 
1348  os << nDir << "</li>\r\n";
1349 
1350  os << " <li>Total Space: ";
1351  sRep = QString("%L1").arg(nTotal) + " MB";
1352  os << sRep << "</li>\r\n";
1353 
1354  os << " <li>Space Used: ";
1355  sRep = QString("%L1").arg(nUsed) + " MB";
1356  os << sRep << "</li>\r\n";
1357 
1358  os << " <li>Space Free: ";
1359  sRep = QString("%L1").arg(nFree) + " MB";
1360  os << sRep << "</li>\r\n";
1361 
1362  os << " </ul>\r\n"
1363  << " </li>\r\n";
1364  }
1365 
1366  }
1367 
1368  node = node.nextSibling();
1369  }
1370 
1371  os << " </ul>\r\n";
1372 
1373  // Guide Info ---------------------
1374 
1375  node = info.namedItem( "Guide" );
1376 
1377  if (!node.isNull())
1378  {
1379  QDomElement e = node.toElement();
1380 
1381  if (!e.isNull())
1382  {
1383  int nDays = e.attribute( "guideDays", "0" ).toInt();
1384  QString sStart = e.attribute( "start" , "" );
1385  QString sEnd = e.attribute( "end" , "" );
1386  QString sStatus = e.attribute( "status" , "" );
1387  QDateTime next = MythDate::fromString( e.attribute( "next" , "" ));
1388  QString sNext = next.isNull() ? "" :
1390  QString sMsg = "";
1391 
1392  QDateTime thru = MythDate::fromString( e.attribute( "guideThru", "" ));
1393 
1394  QDomText text = e.firstChild().toText();
1395 
1396  QString mfdblrs =
1397  gCoreContext->GetSetting("mythfilldatabaseLastRunStart");
1398  QDateTime lastrunstart = MythDate::fromString(mfdblrs);
1399 
1400  if (!text.isNull())
1401  sMsg = text.nodeValue();
1402 
1403  os << " Last mythfilldatabase run started on " << sStart
1404  << " and ";
1405 
1406  if (sEnd < sStart)
1407  os << "is ";
1408  else
1409  os << "ended on " << sEnd << ". ";
1410 
1411  os << sStatus << "<br />\r\n";
1412 
1413  if (!next.isNull() && next >= lastrunstart)
1414  {
1415  os << " Suggested next mythfilldatabase run: "
1416  << sNext << ".<br />\r\n";
1417  }
1418 
1419  if (!thru.isNull())
1420  {
1421  os << " There's guide data until "
1423 
1424  if (nDays > 0)
1425  os << " " << QObject::tr("(%n day(s))", "", nDays);
1426 
1427  os << ".";
1428 
1429  if (nDays <= 3)
1430  os << " <strong>WARNING</strong>: is mythfilldatabase running?";
1431  }
1432  else
1433  os << " There's <strong>no guide data</strong> available! "
1434  << "Have you run mythfilldatabase?";
1435  }
1436  }
1437  os << "\r\n </div>\r\n";
1438 
1439  return( 1 );
1440 }
1441 
1442 int HttpStatus::PrintMiscellaneousInfo( QTextStream &os, const QDomElement& info )
1443 {
1444  if (info.isNull())
1445  return( 0 );
1446 
1447  // Miscellaneous information
1448 
1449  QDomNodeList nodes = info.elementsByTagName("Information");
1450  uint count = nodes.count();
1451  if (count > 0)
1452  {
1453  QString display, linebreak;
1454  //QString name, value;
1455  os << "<div class=\"content\">\r\n"
1456  << " <h2 class=\"status\">Miscellaneous</h2>\r\n";
1457  for (unsigned int i = 0; i < count; i++)
1458  {
1459  QDomNode node = nodes.item(i);
1460  if (node.isNull())
1461  continue;
1462 
1463  QDomElement e = node.toElement();
1464  if (e.isNull())
1465  continue;
1466 
1467  display = e.attribute("display", "");
1468  //name = e.attribute("name", "");
1469  //value = e.attribute("value", "");
1470 
1471  if (display.isEmpty())
1472  continue;
1473 
1474  // Only include HTML line break if display value doesn't already
1475  // contain breaks.
1476  if (display.contains("<p>", Qt::CaseInsensitive) ||
1477  display.contains("<br", Qt::CaseInsensitive))
1478  {
1479  // matches <BR> or <br /
1480  linebreak = "\r\n";
1481  }
1482  else
1483  linebreak = "<br />\r\n";
1484 
1485  os << " " << display << linebreak;
1486  }
1487  os << "</div>\r\n";
1488  }
1489 
1490  return( 1 );
1491 }
1492 
1493 void HttpStatus::FillProgramInfo(QDomDocument *pDoc,
1494  QDomNode &node,
1495  ProgramInfo *pInfo,
1496  bool bIncChannel /* = true */,
1497  bool bDetails /* = true */)
1498 {
1499  if ((pDoc == nullptr) || (pInfo == nullptr))
1500  return;
1501 
1502  // Build Program Element
1503 
1504  QDomElement program = pDoc->createElement( "Program" );
1505  node.appendChild( program );
1506 
1507  program.setAttribute( "startTime" ,
1509  program.setAttribute( "endTime" , pInfo->GetScheduledEndTime(MythDate::ISODate));
1510  program.setAttribute( "title" , pInfo->GetTitle() );
1511  program.setAttribute( "subTitle" , pInfo->GetSubtitle());
1512  program.setAttribute( "category" , pInfo->GetCategory());
1513  program.setAttribute( "catType" , pInfo->GetCategoryTypeString());
1514  program.setAttribute( "repeat" , static_cast<int>(pInfo->IsRepeat()));
1515 
1516  if (bDetails)
1517  {
1518 
1519  program.setAttribute( "seriesId" , pInfo->GetSeriesID() );
1520  program.setAttribute( "programId" , pInfo->GetProgramID() );
1521  program.setAttribute( "stars" , pInfo->GetStars() );
1522  program.setAttribute( "fileSize" ,
1523  QString::number( pInfo->GetFilesize() ));
1524  program.setAttribute( "lastModified",
1526  program.setAttribute( "programFlags", pInfo->GetProgramFlags() );
1527  program.setAttribute( "hostname" , pInfo->GetHostname() );
1528 
1529  if (pInfo->GetOriginalAirDate().isValid())
1530  program.setAttribute(
1531  "airdate", pInfo->GetOriginalAirDate().toString());
1532 
1533  QDomText textNode = pDoc->createTextNode( pInfo->GetDescription() );
1534  program.appendChild( textNode );
1535 
1536  }
1537 
1538  if ( bIncChannel )
1539  {
1540  // Build Channel Child Element
1541 
1542  QDomElement channel = pDoc->createElement( "Channel" );
1543  program.appendChild( channel );
1544 
1545  FillChannelInfo( channel, pInfo, bDetails );
1546  }
1547 
1548  // Build Recording Child Element
1549 
1550  if ( pInfo->GetRecordingStatus() != RecStatus::Unknown )
1551  {
1552  QDomElement recording = pDoc->createElement( "Recording" );
1553  program.appendChild( recording );
1554 
1555  recording.setAttribute( "recStatus" ,
1556  pInfo->GetRecordingStatus() );
1557  recording.setAttribute( "recPriority" ,
1558  pInfo->GetRecordingPriority() );
1559  recording.setAttribute( "recStartTs" ,
1561  recording.setAttribute( "recEndTs" ,
1563 
1564  if (bDetails)
1565  {
1566  recording.setAttribute( "recordId" ,
1567  pInfo->GetRecordingRuleID() );
1568  recording.setAttribute( "recGroup" ,
1569  pInfo->GetRecordingGroup() );
1570  recording.setAttribute( "playGroup" ,
1571  pInfo->GetPlaybackGroup() );
1572  recording.setAttribute( "recType" ,
1573  pInfo->GetRecordingRuleType() );
1574  recording.setAttribute( "dupInType" ,
1575  pInfo->GetDuplicateCheckSource() );
1576  recording.setAttribute( "dupMethod" ,
1577  pInfo->GetDuplicateCheckMethod() );
1578  recording.setAttribute( "encoderId" ,
1579  pInfo->GetInputID() );
1580  const RecordingInfo ri(*pInfo);
1581  recording.setAttribute( "recProfile" ,
1583  //recording.setAttribute( "preRollSeconds", m_nPreRollSeconds );
1584  }
1585  }
1586 }
1587 
1589 //
1591 
1592 void HttpStatus::FillChannelInfo( QDomElement &channel,
1593  ProgramInfo *pInfo,
1594  bool bDetails /* = true */ )
1595 {
1596  if (pInfo)
1597  {
1598 /*
1599  QString sHostName = gCoreContext->GetHostName();
1600  QString sPort = gCoreContext->GetSettingOnHost( "BackendStatusPort",
1601  sHostName);
1602  QString sIconURL = QString( "http://%1:%2/getChannelIcon?ChanId=%3" )
1603  .arg( sHostName )
1604  .arg( sPort )
1605  .arg( pInfo->chanid );
1606 */
1607 
1608  channel.setAttribute( "chanId" , pInfo->GetChanID() );
1609  channel.setAttribute( "chanNum" , pInfo->GetChanNum());
1610  channel.setAttribute( "callSign" , pInfo->GetChannelSchedulingID());
1611  //channel.setAttribute( "iconURL" , sIconURL );
1612  channel.setAttribute( "channelName", pInfo->GetChannelName());
1613 
1614  if (bDetails)
1615  {
1616  channel.setAttribute( "chanFilters",
1617  pInfo->GetChannelPlaybackFilters() );
1618  channel.setAttribute( "sourceId" , pInfo->GetSourceID() );
1619  channel.setAttribute( "inputId" , pInfo->GetInputID() );
1620  channel.setAttribute( "commFree" ,
1621  (pInfo->IsCommercialFree()) ? 1 : 0 );
1622  }
1623  }
1624 }
1625 
1626 
1627 
1628 
1629 // vim:set shiftwidth=4 tabstop=4 expandtab:
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
float GetStars(void) const
Definition: programinfo.h:434
void Run(time_t timeout=0)
Runs a command inside the /bin/sh shell. Returns immediately.
QStringList GetBasePaths() override
Definition: httpstatus.cpp:80
void FillProgramInfo(QDomDocument *pDoc, QDomNode &node, ProgramInfo *pInfo, bool bIncChannel=true, bool bDetails=true)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
uint GetInputID(void) const
Definition: programinfo.h:455
QString m_sBaseUrl
Definition: httprequest.h:123
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:63
int PrintMachineInfo(QTextStream &os, const QDomElement &info)
RecordingDupMethodType GetDuplicateCheckMethod(void) const
What should be compared to determine if two programs are the same?
Definition: programinfo.h:451
static QString setting_to_localtime(const char *setting)
Definition: httpstatus.cpp:166
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:378
allow access to stdout
Definition: mythsystem.h:39
QMap< QString, DeviceLocation * > EntryMap
Key == Unique Service Name (USN)
Definition: ssdpcache.h:28
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
bool ProcessRequest(HTTPRequest *pRequest) override
Definition: httpstatus.cpp:89
virtual uint64_t GetFilesize(void) const
Default local time.
Definition: mythdate.h:17
uint GetSourceID(void) const
Definition: programinfo.h:454
static QString JobText(int jobType)
Definition: jobqueue.cpp:1118
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
QString m_sMethod
Definition: httprequest.h:125
QStringMap m_mapRespHeaders
Definition: httprequest.h:149
QString GetTitle(void) const
Definition: programinfo.h:353
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:34
long m_nResponseStatus
Definition: httprequest.h:148
bool IsCommercialFree(void) const
Definition: programinfo.h:470
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:80
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
AutoExpire * m_pExpirer
Definition: httpstatus.h:48
int GetRecordingPriority(void) const
Definition: programinfo.h:432
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:368
void FillStatusXML(QDomDocument *pDoc)
Definition: httpstatus.cpp:173
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:50
QString m_sResourceUrl
Definition: httprequest.h:124
QString GetChannelPlaybackFilters(void) const
Definition: programinfo.h:379
static int GetJobsInQueue(QMap< int, JobQueueEntry > &jobs, int findJobs=JOB_LIST_NOT_DONE)
Definition: jobqueue.cpp:1279
RecList::const_iterator RecConstIter
Definition: mythscheduler.h:16
unsigned char r
Definition: ParseText.cpp:329
void GetStatusXML(HTTPRequest *pRequest)
Definition: httpstatus.cpp:129
int PrintMiscellaneousInfo(QTextStream &os, const QDomElement &info)
int PrintFrontends(QTextStream &os, const QDomElement &frontends)
Definition: httpstatus.cpp:980
QDate GetOriginalAirDate(void) const
Definition: programinfo.h:420
QString GetMasterServerIP(void)
Returns the Master Backend IP address If the address is an IPv6 address, the scope Id is removed.
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:382
QVariant value(int i) const
Definition: mythdbcon.h:198
void FillChannelInfo(QDomElement &channel, ProgramInfo *pInfo, bool bDetails=true)
Holds information on recordings and videos.
Definition: programinfo.h:66
void GetEntryMap(EntryMap &)
Returns a copy of the EntryMap.
Definition: ssdpcache.cpp:85
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
Definition: tv.h:84
int PrintEncoderStatus(QTextStream &os, const QDomElement &encoders)
Definition: httpstatus.cpp:705
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:433
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:375
uint32_t GetProgramFlags(void) const
Definition: programinfo.h:464
Default local time.
Definition: mythdate.h:19
QString GetDescription(void) const
Definition: programinfo.h:357
HttpStatus(QMap< int, EncoderLink * > *tvList, Scheduler *sched, AutoExpire *expirer, bool bIsMaster)
Definition: httpstatus.cpp:48
run process through shell
Definition: mythsystem.h:41
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
QByteArray & ReadAll()
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
QString GetSubtitle(void) const
Definition: programinfo.h:355
static QString StatusText(int status)
Definition: jobqueue.cpp:1137
bool IsRepeat(void) const
Definition: programinfo.h:478
Default local time.
Definition: mythdate.h:16
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:48
QString GetRecordingGroup(void) const
Definition: programinfo.h:411
QString GetMasterHostName(void)
SleepStatus
SleepStatus is an enumeration of the awake/sleep status of a slave.
Definition: tv.h:97
void BackendQueryDiskSpace(QStringList &strlist, bool consolidated, bool allHosts)
string hostname
Definition: caa.py:17
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
QString GetCategoryTypeString(void) const
Returns catType as a string.
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:389
int m_nPreRollSeconds
Definition: httpstatus.h:51
const char * name
Definition: ParseText.cpp:328
#define getloadavg(x, y)
Definition: compat.h:322
QMap< int, EncoderLink * > * m_pEncoders
Definition: httpstatus.h:47
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
QString GetPlaybackGroup(void) const
Definition: programinfo.h:412
int PrintBackends(QTextStream &os, const QDomElement &backends)
A slave is considered asleep when it is not awake and not undefined.
Definition: tv.h:104
uint Wait(time_t timeout=0)
void GetStatusHTML(HTTPRequest *pRequest)
Definition: httpstatus.cpp:153
QString GetProgramRecordingProfile(void) const
Returns recording profile name that will be, or was used, for this program, creating "record" field i...
QString GetSeriesID(void) const
Definition: programinfo.h:427
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
PictureAttribute next(PictureAttributeSupported supported, PictureAttribute attribute)
int GetNumSetting(const QString &key, int defaultval=0)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
MainServer * m_pMainServer
Definition: httpstatus.h:49
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:439
bool GetBoolSetting(const QString &key, bool defaultval=false)
void PrintStatus(QTextStream &os, QDomDocument *pDoc)
Definition: httpstatus.cpp:622
int PrintJobQueue(QTextStream &os, const QDomElement &jobs)
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:443
Used to expire recordings to make space for new recordings.
Definition: autoexpire.h:61
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:364
AutoExpire * expirer
uint GetRecordingRuleID(void) const
Definition: programinfo.h:441
Default local time.
Definition: mythdate.h:20
A slave's sleep status is undefined when it has never connected to the master backend or is not able ...
Definition: tv.h:117
QString GetProgramID(void) const
Definition: programinfo.h:428
QBuffer m_response
Definition: httprequest.h:153
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:16
Default UTC, database format.
Definition: mythdate.h:24
HttpResponseType m_eResponseType
Definition: httprequest.h:145
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:396
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:404
HttpStatusMethod
Definition: httpstatus.h:21
int GetMasterServerStatusPort(void)
Returns the Master Backend status port If no master server status port has been defined in the databa...
Scheduler * sched
QDateTime GetLastModifiedTime(void) const
Definition: programinfo.h:421
Add year to string if not included.
Definition: mythdate.h:22
HttpStatusMethod GetMethod(const QString &sURI)
Definition: httpstatus.cpp:66
QString GetHostname(void) const
Definition: programinfo.h:413
std::deque< RecordingInfo * > RecList
Definition: mythscheduler.h:10
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static SSDPCacheEntries * Find(const QString &sURI)
Definition: ssdp.h:129
Scheduler * m_pSched
Definition: httpstatus.h:46
QString GetCategory(void) const
Definition: programinfo.h:361
int PrintScheduled(QTextStream &os, const QDomElement &scheduled)
Definition: httpstatus.cpp:849
RecordingDupInType GetDuplicateCheckSource(void) const
Where should we check for duplicates?
Definition: programinfo.h:447
bool IsMasterBackend(void)
is this the actual MBE process
JobQueue * jobqueue
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:108
QString GetHostName(void)
bool GetAllPending(RecList &retList, int recRuleId=0) const
Definition: scheduler.cpp:1752
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
QMap< int, EncoderLink * > tvList
Default UTC.
Definition: mythdate.h:14
#define output
bool m_bIsMaster
Definition: httpstatus.h:50
unsigned char g
Definition: ParseText.cpp:329