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