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