MythTV  0.28pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
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->GetCardID() );
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() <= rsWillRecord) &&
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->GetSetting("MasterServerIP");
334  QString masterport = gCoreContext->GetSettingOnHost("BackendStatusPort", masterhost, "6544");
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);
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  double rgdAverages[3];
524 
525  if (getloadavg(rgdAverages, 3) != -1)
526  {
527  load.setAttribute("avg1", rgdAverages[0]);
528  load.setAttribute("avg2", rgdAverages[1]);
529  load.setAttribute("avg3", rgdAverages[2]);
530  }
531 
532  // Guide Data ---------------------
533 
534  QDateTime GuideDataThrough;
535 
536  MSqlQuery query(MSqlQuery::InitCon());
537  query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;");
538 
539  if (query.exec() && query.next())
540  {
541  GuideDataThrough = MythDate::fromString(query.value(0).toString());
542  }
543 
544  guide.setAttribute("start",
545  setting_to_localtime("mythfilldatabaseLastRunStart"));
546  guide.setAttribute("end",
547  setting_to_localtime("mythfilldatabaseLastRunEnd"));
548  guide.setAttribute("status",
549  gCoreContext->GetSetting("mythfilldatabaseLastRunStatus"));
550  if (gCoreContext->GetNumSetting("MythFillGrabberSuggestsTime", 0))
551  {
552  guide.setAttribute("next",
553  gCoreContext->GetSetting("MythFillSuggestedRunTime"));
554  }
555 
556  if (!GuideDataThrough.isNull())
557  {
558  guide.setAttribute("guideThru",
559  QDateTime(GuideDataThrough).toString(Qt::ISODate));
560  guide.setAttribute("guideDays", qdtNow.daysTo(GuideDataThrough));
561  }
562 
563  QDomText dataDirectMessage =
564  pDoc->createTextNode(gCoreContext->GetSetting("DataDirectMessage"));
565  guide.appendChild(dataDirectMessage);
566 
567  // Add Miscellaneous information
568 
569  QString info_script = gCoreContext->GetSetting("MiscStatusScript");
570  if ((!info_script.isEmpty()) && (info_script != "none"))
571  {
572  QDomElement misc = pDoc->createElement("Miscellaneous");
573  root.appendChild(misc);
574 
575  uint flags = kMSRunShell | kMSStdOut;
576  MythSystemLegacy ms(info_script, flags);
577  ms.Run(10);
578  if (ms.Wait() != GENERIC_EXIT_OK)
579  {
580  LOG(VB_GENERAL, LOG_ERR,
581  QString("Error running miscellaneous "
582  "status information script: %1").arg(info_script));
583  return;
584  }
585 
586  QByteArray input = ms.ReadAll();
587 
588  QStringList output = QString(input).split('\n',
589  QString::SkipEmptyParts);
590 
591  QStringList::iterator iter;
592  for (iter = output.begin(); iter != output.end(); ++iter)
593  {
594  QDomElement info = pDoc->createElement("Information");
595 
596  QStringList list = (*iter).split("[]:[]");
597  unsigned int size = list.size();
598  unsigned int hasAttributes = 0;
599 
600  if ((size > 0) && (!list[0].isEmpty()))
601  {
602  info.setAttribute("display", list[0]);
603  hasAttributes++;
604  }
605  if ((size > 1) && (!list[1].isEmpty()))
606  {
607  info.setAttribute("name", list[1]);
608  hasAttributes++;
609  }
610  if ((size > 2) && (!list[2].isEmpty()))
611  {
612  info.setAttribute("value", list[2]);
613  hasAttributes++;
614  }
615 
616  if (hasAttributes > 0)
617  misc.appendChild(info);
618  }
619  }
620 }
621 
623 //
625 
626 void HttpStatus::PrintStatus( QTextStream &os, QDomDocument *pDoc )
627 {
628  os.setCodec("UTF-8");
629 
630  QDateTime qdtNow = MythDate::current();
631 
632  QDomElement docElem = pDoc->documentElement();
633 
634  os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
635  << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
636  << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
637  << " xml:lang=\"en\" lang=\"en\">\r\n"
638  << "<head>\r\n"
639  << " <meta http-equiv=\"Content-Type\""
640  << "content=\"text/html; charset=UTF-8\" />\r\n"
641  << " <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
642  << " <title>MythTV Status - "
643  << docElem.attribute( "date", MythDate::toString(qdtNow, MythDate::kDateShort) )
644  << " "
645  << docElem.attribute( "time", MythDate::toString(qdtNow, MythDate::kTime) ) << " - "
646  << docElem.attribute( "version", MYTH_BINARY_VERSION ) << "</title>\r\n"
647  << "</head>\r\n"
648  << "<body bgcolor=\"#fff\">\r\n"
649  << "<div class=\"status\">\r\n"
650  << " <h1 class=\"status\">MythTV Status</h1>\r\n";
651 
652  // encoder information ---------------------
653 
654  QDomNode node = docElem.namedItem( "Encoders" );
655 
656  if (!node.isNull())
657  PrintEncoderStatus( os, node.toElement() );
658 
659  // upcoming shows --------------------------
660 
661  node = docElem.namedItem( "Scheduled" );
662 
663  if (!node.isNull())
664  PrintScheduled( os, node.toElement());
665 
666  // Frontends
667 
668  node = docElem.namedItem( "Frontends" );
669 
670  if (!node.isNull())
671  PrintFrontends (os, node.toElement());
672 
673  // Backends
674 
675  node = docElem.namedItem( "Backends" );
676 
677  if (!node.isNull())
678  PrintBackends (os, node.toElement());
679 
680  // Job Queue Entries -----------------------
681 
682  node = docElem.namedItem( "JobQueue" );
683 
684  if (!node.isNull())
685  PrintJobQueue( os, node.toElement());
686 
687  // Machine information ---------------------
688 
689  node = docElem.namedItem( "MachineInfo" );
690 
691  if (!node.isNull())
692  PrintMachineInfo( os, node.toElement());
693 
694  // Miscellaneous information ---------------
695 
696  node = docElem.namedItem( "Miscellaneous" );
697 
698  if (!node.isNull())
699  PrintMiscellaneousInfo( os, node.toElement());
700 
701  os << "\r\n</div>\r\n</body>\r\n</html>\r\n";
702 
703 }
704 
706 //
708 
709 int HttpStatus::PrintEncoderStatus( QTextStream &os, QDomElement encoders )
710 {
711  int nNumEncoders = 0;
712 
713  if (encoders.isNull())
714  return 0;
715 
716  os << " <div class=\"content\">\r\n"
717  << " <h2 class=\"status\">Encoder Status</h2>\r\n";
718 
719  QDomNode node = encoders.firstChild();
720 
721  while (!node.isNull())
722  {
723  QDomElement e = node.toElement();
724 
725  if (!e.isNull())
726  {
727  if (e.tagName() == "Encoder")
728  {
729  QString sIsLocal = (e.attribute( "local" , "remote" )== "1")
730  ? "local" : "remote";
731  QString sCardId = e.attribute( "id" , "0" );
732  QString sHostName = e.attribute( "hostname" , "Unknown");
733  bool bConnected= e.attribute( "connected", "0" ).toInt();
734 
735  bool bIsLowOnFreeSpace=e.attribute( "lowOnFreeSpace", "0").toInt();
736 
737  QString sDevlabel = e.attribute( "devlabel", "[ UNKNOWN ]");
738 
739  os << " Encoder " << sCardId << " " << sDevlabel
740  << " is " << sIsLocal << " on " << sHostName;
741 
742  if ((sIsLocal == "remote") && !bConnected)
743  {
744  SleepStatus sleepStatus =
745  (SleepStatus) e.attribute("sleepstatus",
746  QString((int)sStatus_Undefined)).toInt();
747 
748  if (sleepStatus == sStatus_Asleep)
749  os << " (currently asleep).<br />";
750  else
751  os << " (currently not connected).<br />";
752 
753  node = node.nextSibling();
754  continue;
755  }
756 
757  nNumEncoders++;
758 
759  TVState encState = (TVState) e.attribute( "state", "0").toInt();
760 
761  switch( encState )
762  {
764  os << " and is watching Live TV";
765  break;
766 
769  os << " and is recording";
770  break;
771 
772  default:
773  os << " and is not recording.";
774  break;
775  }
776 
777  // Display first Program Element listed under the encoder
778 
779  QDomNode tmpNode = e.namedItem( "Program" );
780 
781  if (!tmpNode.isNull())
782  {
783  QDomElement program = tmpNode.toElement();
784 
785  if (!program.isNull())
786  {
787  os << " '" << program.attribute( "title", "Unknown" ) << "'";
788 
789  // Get Channel information
790 
791  tmpNode = program.namedItem( "Channel" );
792 
793  if (!tmpNode.isNull())
794  {
795  QDomElement channel = tmpNode.toElement();
796 
797  if (!channel.isNull())
798  os << " on "
799  << channel.attribute( "callSign", "unknown" );
800  }
801 
802  // Get Recording Information (if any)
803 
804  tmpNode = program.namedItem( "Recording" );
805 
806  if (!tmpNode.isNull())
807  {
808  QDomElement recording = tmpNode.toElement();
809 
810  if (!recording.isNull())
811  {
812  QDateTime endTs = MythDate::fromString(
813  recording.attribute( "recEndTs", "" ));
814 
815  os << ". This recording ";
816  if (endTs < MythDate::current())
817  os << "was ";
818  else
819  os << "is ";
820 
821  os << "scheduled to end at "
822  << MythDate::toString(endTs,
824  }
825  }
826  }
827 
828  os << ".";
829  }
830 
831  if (bIsLowOnFreeSpace)
832  {
833  os << " <strong>WARNING</strong>:"
834  << " This backend is low on free disk space!";
835  }
836 
837  os << "<br />\r\n";
838  }
839  }
840 
841  node = node.nextSibling();
842  }
843 
844  os << " </div>\r\n\r\n";
845 
846  return( nNumEncoders );
847 }
848 
850 //
852 
853 int HttpStatus::PrintScheduled( QTextStream &os, QDomElement scheduled )
854 {
855  QDateTime qdtNow = MythDate::current();
856 
857  if (scheduled.isNull())
858  return( 0 );
859 
860  int nNumRecordings= scheduled.attribute( "count", "0" ).toInt();
861 
862  os << " <div class=\"content\">\r\n"
863  << " <h2 class=\"status\">Schedule</h2>\r\n";
864 
865  if (nNumRecordings == 0)
866  {
867  os << " There are no shows scheduled for recording.\r\n"
868  << " </div>\r\n";
869  return( 0 );
870  }
871 
872  os << " The next " << nNumRecordings << " show" << (nNumRecordings == 1 ? "" : "s" )
873  << " that " << (nNumRecordings == 1 ? "is" : "are")
874  << " scheduled for recording:\r\n";
875 
876  os << " <div class=\"schedule\">\r\n";
877 
878  // Iterate through all scheduled programs
879 
880  QDomNode node = scheduled.firstChild();
881 
882  while (!node.isNull())
883  {
884  QDomElement e = node.toElement();
885 
886  if (!e.isNull())
887  {
888  QDomNode recNode = e.namedItem( "Recording" );
889  QDomNode chanNode = e.namedItem( "Channel" );
890 
891  if ((e.tagName() == "Program") && !recNode.isNull() &&
892  !chanNode.isNull())
893  {
894  QDomElement r = recNode.toElement();
895  QDomElement c = chanNode.toElement();
896 
897  QString sTitle = e.attribute( "title" , "" );
898  QString sSubTitle = e.attribute( "subTitle", "" );
899  QDateTime airDate = MythDate::fromString( e.attribute( "airdate" ,"" ));
900  QDateTime startTs = MythDate::fromString( e.attribute( "startTime" ,"" ));
901  QDateTime endTs = MythDate::fromString( e.attribute( "endTime" ,"" ));
902  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
903 // QDateTime recEndTs = MythDate::fromString( r.attribute( "recEndTs" ,"" ));
904  int nPreRollSecs = r.attribute( "preRollSeconds", "0" ).toInt();
905  int nEncoderId = r.attribute( "encoderId" , "0" ).toInt();
906  QString sProfile = r.attribute( "recProfile" , "" );
907  QString sChanName = c.attribute( "channelName" , "" );
908  QString sDesc = "";
909 
910  QDomText text = e.firstChild().toText();
911  if (!text.isNull())
912  sDesc = text.nodeValue();
913 
914  // Build Time to recording start.
915 
916  int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
917 
918  //since we're not displaying seconds
919 
920  nTotalSecs -= 60;
921 
922  int nTotalDays = nTotalSecs / 86400;
923  int nTotalHours = (nTotalSecs / 3600)
924  - (nTotalDays * 24);
925  int nTotalMins = (nTotalSecs / 60) % 60;
926 
927  QString sTimeToStart = "in";
928 
929  sTimeToStart += QObject::tr(" %n day(s),", "", nTotalDays );
930  sTimeToStart += QObject::tr(" %n hour(s) and", "", nTotalHours);
931  sTimeToStart += QObject::tr(" %n minute(s)", "", nTotalMins);
932 
933  if ( nTotalHours == 0 && nTotalMins == 0)
934  sTimeToStart = QObject::tr("within one minute", "Recording starting");
935 
936  if ( nTotalSecs < 0)
937  sTimeToStart = QObject::tr("soon", "Recording starting");
938 
939  // Output HTML
940 
941  os << " <a href=\"#\">";
942  os << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
944  MythDate::kSimplify) << " "
945  << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
946  MythDate::kTime) << " - ";
947 
948  if (nEncoderId > 0)
949  os << "Encoder " << nEncoderId << " - ";
950 
951  os << sChanName << " - " << sTitle << "<br />"
952  << "<span><strong>" << sTitle << "</strong> ("
953  << MythDate::toString(startTs, MythDate::kTime) << "-"
954  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
955 
956  if ( !sSubTitle.isEmpty())
957  os << "<em>" << sSubTitle << "</em><br /><br />";
958 
959  if ( airDate.isValid())
960  os << "Orig. Airdate: "
963  << "<br /><br />";
964 
965  os << sDesc << "<br /><br />"
966  << "This recording will start " << sTimeToStart
967  << " using encoder " << nEncoderId << " with the '"
968  << sProfile << "' profile.</span></a><hr />\r\n";
969  }
970  }
971 
972  node = node.nextSibling();
973  }
974  os << " </div>\r\n";
975  os << " </div>\r\n\r\n";
976 
977  return( nNumRecordings );
978 }
979 
981 //
983 
984 int HttpStatus::PrintFrontends( QTextStream &os, QDomElement frontends )
985 {
986  if (frontends.isNull())
987  return( 0 );
988 
989  int nNumFES= frontends.attribute( "count", "0" ).toInt();
990 
991  if (nNumFES < 1)
992  return( 0 );
993 
994 
995  os << " <div class=\"content\">\r\n"
996  << " <h2 class=\"status\">Frontends</h2>\r\n";
997 
998  QDomNode node = frontends.firstChild();
999  while (!node.isNull())
1000  {
1001  QDomElement e = node.toElement();
1002 
1003  if (!e.isNull())
1004  {
1005  QString name = e.attribute( "name" , "" );
1006  QString url = e.attribute( "url" , "" );
1007  os << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1008  }
1009 
1010  node = node.nextSibling();
1011  }
1012 
1013  os << " </div>\r\n\r\n";
1014 
1015  return nNumFES;
1016 }
1017 
1019 //
1021 
1022 int HttpStatus::PrintBackends( QTextStream &os, QDomElement backends )
1023 {
1024  if (backends.isNull())
1025  return( 0 );
1026 
1027  int nNumBES= backends.attribute( "count", "0" ).toInt();
1028 
1029  if (nNumBES < 1)
1030  return( 0 );
1031 
1032 
1033  os << " <div class=\"content\">\r\n"
1034  << " <h2 class=\"status\">Other Backends</h2>\r\n";
1035 
1036  QDomNode node = backends.firstChild();
1037  while (!node.isNull())
1038  {
1039  QDomElement e = node.toElement();
1040 
1041  if (!e.isNull())
1042  {
1043  QString type = e.attribute( "type", "" );
1044  QString name = e.attribute( "name" , "" );
1045  QString url = e.attribute( "url" , "" );
1046  os << type << ": " << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1047  }
1048 
1049  node = node.nextSibling();
1050  }
1051 
1052  os << " </div>\r\n\r\n";
1053 
1054  return nNumBES;
1055 }
1056 
1058 //
1060 
1061 int HttpStatus::PrintJobQueue( QTextStream &os, QDomElement jobs )
1062 {
1063  if (jobs.isNull())
1064  return( 0 );
1065 
1066  int nNumJobs= jobs.attribute( "count", "0" ).toInt();
1067 
1068  os << " <div class=\"content\">\r\n"
1069  << " <h2 class=\"status\">Job Queue</h2>\r\n";
1070 
1071  if (nNumJobs != 0)
1072  {
1073  QString statusColor;
1074  QString jobColor;
1075 
1076  os << " Jobs currently in Queue or recently ended:\r\n<br />"
1077  << " <div class=\"schedule\">\r\n";
1078 
1079 
1080  QDomNode node = jobs.firstChild();
1081 
1082  while (!node.isNull())
1083  {
1084  QDomElement e = node.toElement();
1085 
1086  if (!e.isNull())
1087  {
1088  QDomNode progNode = e.namedItem( "Program" );
1089 
1090  if ((e.tagName() == "Job") && !progNode.isNull() )
1091  {
1092  QDomElement p = progNode.toElement();
1093 
1094  QDomNode recNode = p.namedItem( "Recording" );
1095  QDomNode chanNode = p.namedItem( "Channel" );
1096 
1097  QDomElement r = recNode.toElement();
1098  QDomElement c = chanNode.toElement();
1099 
1100  int nType = e.attribute( "type" , "0" ).toInt();
1101  int nStatus = e.attribute( "status", "0" ).toInt();
1102 
1103  switch( nStatus )
1104  {
1105  case JOB_ABORTED:
1106  statusColor = " class=\"jobaborted\"";
1107  jobColor = "";
1108  break;
1109 
1110  case JOB_ERRORED:
1111  statusColor = " class=\"joberrored\"";
1112  jobColor = " class=\"joberrored\"";
1113  break;
1114 
1115  case JOB_FINISHED:
1116  statusColor = " class=\"jobfinished\"";
1117  jobColor = " class=\"jobfinished\"";
1118  break;
1119 
1120  case JOB_RUNNING:
1121  statusColor = " class=\"jobrunning\"";
1122  jobColor = " class=\"jobrunning\"";
1123  break;
1124 
1125  default:
1126  statusColor = " class=\"jobqueued\"";
1127  jobColor = " class=\"jobqueued\"";
1128  break;
1129  }
1130 
1131  QString sTitle = p.attribute( "title" , "" ); //.replace(QRegExp("\""), "&quot;");
1132  QString sSubTitle = p.attribute( "subTitle", "" );
1133  QDateTime startTs = MythDate::fromString( p.attribute( "startTime" ,"" ));
1134  QDateTime endTs = MythDate::fromString( p.attribute( "endTime" ,"" ));
1135  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
1136  QDateTime statusTime = MythDate::fromString( e.attribute( "statusTime","" ));
1137  QDateTime schedRunTime = MythDate::fromString( e.attribute( "schedTime","" ));
1138  QString sHostname = e.attribute( "hostname", "master" );
1139  QString sComment = "";
1140 
1141  QDomText text = e.firstChild().toText();
1142  if (!text.isNull())
1143  sComment = text.nodeValue();
1144 
1145  os << "<a href=\"javascript:void(0)\">"
1146  << MythDate::toString(recStartTs, MythDate::kDateFull |
1148  << " - "
1149  << sTitle << " - <font" << jobColor << ">"
1150  << JobQueue::JobText( nType ) << "</font><br />"
1151  << "<span><strong>" << sTitle << "</strong> ("
1152  << MythDate::toString(startTs, MythDate::kTime) << "-"
1153  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
1154 
1155  if (!sSubTitle.isEmpty())
1156  os << "<em>" << sSubTitle << "</em><br /><br />";
1157 
1158  os << "Job: " << JobQueue::JobText( nType ) << "<br />";
1159 
1160  if (schedRunTime > MythDate::current())
1161  os << "Scheduled Run Time: "
1162  << MythDate::toString(schedRunTime,
1165  << "<br />";
1166 
1167  os << "Status: <font" << statusColor << ">"
1168  << JobQueue::StatusText( nStatus )
1169  << "</font><br />"
1170  << "Status Time: "
1171  << MythDate::toString(statusTime, MythDate::kDateFull |
1173  << "<br />";
1174 
1175  if ( nStatus != JOB_QUEUED)
1176  os << "Host: " << sHostname << "<br />";
1177 
1178  if (!sComment.isEmpty())
1179  os << "<br />Comments:<br />" << sComment << "<br />";
1180 
1181  os << "</span></a><hr />\r\n";
1182  }
1183  }
1184 
1185  node = node.nextSibling();
1186  }
1187  os << " </div>\r\n";
1188  }
1189  else
1190  os << " Job Queue is currently empty.\r\n\r\n";
1191 
1192  os << " </div>\r\n\r\n ";
1193 
1194  return( nNumJobs );
1195 
1196 }
1197 
1199 //
1201 
1202 int HttpStatus::PrintMachineInfo( QTextStream &os, QDomElement info )
1203 {
1204  QString sRep;
1205 
1206  if (info.isNull())
1207  return( 0 );
1208 
1209  os << "<div class=\"content\">\r\n"
1210  << " <h2 class=\"status\">Machine Information</h2>\r\n";
1211 
1212  // load average ---------------------
1213 
1214  QDomNode node = info.namedItem( "Load" );
1215 
1216  if (!node.isNull())
1217  {
1218  QDomElement e = node.toElement();
1219 
1220  if (!e.isNull())
1221  {
1222  double dAvg1 = e.attribute( "avg1" , "0" ).toDouble();
1223  double dAvg2 = e.attribute( "avg2" , "0" ).toDouble();
1224  double dAvg3 = e.attribute( "avg3" , "0" ).toDouble();
1225 
1226  os << " <div class=\"loadstatus\">\r\n"
1227  << " This machine's load average:"
1228  << "\r\n <ul>\r\n <li>"
1229  << "1 Minute: " << dAvg1 << "</li>\r\n"
1230  << " <li>5 Minutes: " << dAvg2 << "</li>\r\n"
1231  << " <li>15 Minutes: " << dAvg3
1232  << "</li>\r\n </ul>\r\n"
1233  << " </div>\r\n";
1234  }
1235  }
1236 
1237  // local drive space ---------------------
1238  node = info.namedItem( "Storage" );
1239  QDomElement storage = node.toElement();
1240  node = storage.firstChild();
1241 
1242  // Loop once until we find id == "total". This should be first, but a loop
1243  // separate from the per-filesystem details loop ensures total is first,
1244  // regardless.
1245  while (!node.isNull())
1246  {
1247  QDomElement g = node.toElement();
1248 
1249  if (!g.isNull() && g.tagName() == "Group")
1250  {
1251  QString id = g.attribute("id", "" );
1252 
1253  if (id == "total")
1254  {
1255  int nFree = g.attribute("free" , "0" ).toInt();
1256  int nTotal = g.attribute("total", "0" ).toInt();
1257  int nUsed = g.attribute("used" , "0" ).toInt();
1258  int nLiveTV = g.attribute("livetv" , "0" ).toInt();
1259  int nDeleted = g.attribute("deleted", "0" ).toInt();
1260  int nExpirable = g.attribute("expirable" , "0" ).toInt();
1261  QString nDir = g.attribute("dir" , "" );
1262 
1263  nDir.replace(QRegExp(","), ", ");
1264 
1265  os << " Disk Usage Summary:<br />\r\n";
1266  os << " <ul>\r\n";
1267 
1268  os << " <li>Total Disk Space:\r\n"
1269  << " <ul>\r\n";
1270  QLocale c(QLocale::C);
1271 
1272  os << " <li>Total Space: ";
1273  sRep = c.toString(nTotal) + " MB";
1274  os << sRep << "</li>\r\n";
1275 
1276  os << " <li>Space Used: ";
1277  sRep = c.toString(nUsed) + " MB";
1278  os << sRep << "</li>\r\n";
1279 
1280  os << " <li>Space Free: ";
1281  sRep = c.toString(nFree) + " MB";
1282  os << sRep << "</li>\r\n";
1283 
1284  if ((nLiveTV + nDeleted + nExpirable) > 0)
1285  {
1286  os << " <li>Space Available "
1287  "After Auto-expire: ";
1288  sRep = c.toString(nFree + nLiveTV +
1289  nDeleted + nExpirable) + " MB";
1290  os << sRep << "\r\n";
1291  os << " <ul>\r\n";
1292  os << " <li>Space Used by LiveTV: ";
1293  sRep = c.toString(nLiveTV) + " MB";
1294  os << sRep << "</li>\r\n";
1295  os << " <li>Space Used by "
1296  "Deleted Recordings: ";
1297  sRep = c.toString(nDeleted) + " MB";
1298  os << sRep << "</li>\r\n";
1299  os << " <li>Space Used by "
1300  "Auto-expirable Recordings: ";
1301  sRep = c.toString(nExpirable) + " MB";
1302  os << sRep << "</li>\r\n";
1303  os << " </ul>\r\n";
1304  os << " </li>\r\n";
1305  }
1306 
1307  os << " </ul>\r\n"
1308  << " </li>\r\n";
1309 
1310  os << " </ul>\r\n";
1311  break;
1312  }
1313  }
1314 
1315  node = node.nextSibling();
1316  }
1317 
1318  // Loop again to handle per-filesystem details.
1319  node = storage.firstChild();
1320 
1321  os << " Disk Usage Details:<br />\r\n";
1322  os << " <ul>\r\n";
1323 
1324 
1325  while (!node.isNull())
1326  {
1327  QDomElement g = node.toElement();
1328 
1329  if (!g.isNull() && g.tagName() == "Group")
1330  {
1331  int nFree = g.attribute("free" , "0" ).toInt();
1332  int nTotal = g.attribute("total", "0" ).toInt();
1333  int nUsed = g.attribute("used" , "0" ).toInt();
1334  QString nDir = g.attribute("dir" , "" );
1335  QString id = g.attribute("id" , "" );
1336 
1337  nDir.replace(QRegExp(","), ", ");
1338 
1339 
1340  if (id != "total")
1341  {
1342 
1343  os << " <li>MythTV Drive #" << id << ":"
1344  << "\r\n"
1345  << " <ul>\r\n";
1346 
1347  if (nDir.contains(','))
1348  os << " <li>Directories: ";
1349  else
1350  os << " <li>Directory: ";
1351 
1352  os << nDir << "</li>\r\n";
1353 
1354  QLocale c(QLocale::C);
1355 
1356  os << " <li>Total Space: ";
1357  sRep = c.toString(nTotal) + " MB";
1358  os << sRep << "</li>\r\n";
1359 
1360  os << " <li>Space Used: ";
1361  sRep = c.toString(nUsed) + " MB";
1362  os << sRep << "</li>\r\n";
1363 
1364  os << " <li>Space Free: ";
1365  sRep = c.toString(nFree) + " MB";
1366  os << sRep << "</li>\r\n";
1367 
1368  os << " </ul>\r\n"
1369  << " </li>\r\n";
1370  }
1371 
1372  }
1373 
1374  node = node.nextSibling();
1375  }
1376 
1377  os << " </ul>\r\n";
1378 
1379  // Guide Info ---------------------
1380 
1381  node = info.namedItem( "Guide" );
1382 
1383  if (!node.isNull())
1384  {
1385  QDomElement e = node.toElement();
1386 
1387  if (!e.isNull())
1388  {
1389  int nDays = e.attribute( "guideDays", "0" ).toInt();
1390  QString sStart = e.attribute( "start" , "" );
1391  QString sEnd = e.attribute( "end" , "" );
1392  QString sStatus = e.attribute( "status" , "" );
1393  QDateTime next = MythDate::fromString( e.attribute( "next" , "" ));
1394  QString sNext = next.isNull() ? "" :
1396  QString sMsg = "";
1397 
1398  QDateTime thru = MythDate::fromString( e.attribute( "guideThru", "" ));
1399 
1400  QDomText text = e.firstChild().toText();
1401 
1402  if (!text.isNull())
1403  sMsg = text.nodeValue();
1404 
1405  os << " Last mythfilldatabase run started on " << sStart
1406  << " and ";
1407 
1408  if (sEnd < sStart)
1409  os << "is ";
1410  else
1411  os << "ended on " << sEnd << ". ";
1412 
1413  os << sStatus << "<br />\r\n";
1414 
1415  if (!next.isNull() && sNext >= sStart)
1416  {
1417  os << " Suggested next mythfilldatabase run: "
1418  << sNext << ".<br />\r\n";
1419  }
1420 
1421  if (!thru.isNull())
1422  {
1423  os << " There's guide data until "
1425 
1426  if (nDays > 0)
1427  os << " " << QObject::tr("(%n day(s))", "", nDays);
1428 
1429  os << ".";
1430 
1431  if (nDays <= 3)
1432  os << " <strong>WARNING</strong>: is mythfilldatabase running?";
1433  }
1434  else
1435  os << " There's <strong>no guide data</strong> available! "
1436  << "Have you run mythfilldatabase?";
1437 
1438  if (!sMsg.isEmpty())
1439  os << "<br />\r\n DataDirect Status: " << sMsg;
1440  }
1441  }
1442  os << "\r\n </div>\r\n";
1443 
1444  return( 1 );
1445 }
1446 
1447 int HttpStatus::PrintMiscellaneousInfo( QTextStream &os, QDomElement info )
1448 {
1449  if (info.isNull())
1450  return( 0 );
1451 
1452  // Miscellaneous information
1453 
1454  QDomNodeList nodes = info.elementsByTagName("Information");
1455  uint count = nodes.count();
1456  if (count > 0)
1457  {
1458  QString display, linebreak;
1459  //QString name, value;
1460  os << "<div class=\"content\">\r\n"
1461  << " <h2 class=\"status\">Miscellaneous</h2>\r\n";
1462  for (unsigned int i = 0; i < count; i++)
1463  {
1464  QDomNode node = nodes.item(i);
1465  if (node.isNull())
1466  continue;
1467 
1468  QDomElement e = node.toElement();
1469  if (e.isNull())
1470  continue;
1471 
1472  display = e.attribute("display", "");
1473  //name = e.attribute("name", "");
1474  //value = e.attribute("value", "");
1475 
1476  if (display.isEmpty())
1477  continue;
1478 
1479  // Only include HTML line break if display value doesn't already
1480  // contain breaks.
1481  if (display.contains("<p>", Qt::CaseInsensitive) ||
1482  display.contains("<br", Qt::CaseInsensitive))
1483  {
1484  // matches <BR> or <br /
1485  linebreak = "\r\n";
1486  }
1487  else
1488  linebreak = "<br />\r\n";
1489 
1490  os << " " << display << linebreak;
1491  }
1492  os << "</div>\r\n";
1493  }
1494 
1495  return( 1 );
1496 }
1497 
1498 void HttpStatus::FillProgramInfo(QDomDocument *pDoc,
1499  QDomNode &node,
1500  ProgramInfo *pInfo,
1501  bool bIncChannel /* = true */,
1502  bool bDetails /* = true */)
1503 {
1504  if ((pDoc == NULL) || (pInfo == NULL))
1505  return;
1506 
1507  // Build Program Element
1508 
1509  QDomElement program = pDoc->createElement( "Program" );
1510  node.appendChild( program );
1511 
1512  program.setAttribute( "startTime" ,
1514  program.setAttribute( "endTime" , pInfo->GetScheduledEndTime(MythDate::ISODate));
1515  program.setAttribute( "title" , pInfo->GetTitle() );
1516  program.setAttribute( "subTitle" , pInfo->GetSubtitle());
1517  program.setAttribute( "category" , pInfo->GetCategory());
1518  program.setAttribute( "catType" , pInfo->GetCategoryTypeString());
1519  program.setAttribute( "repeat" , pInfo->IsRepeat() );
1520 
1521  if (bDetails)
1522  {
1523 
1524  program.setAttribute( "seriesId" , pInfo->GetSeriesID() );
1525  program.setAttribute( "programId" , pInfo->GetProgramID() );
1526  program.setAttribute( "stars" , pInfo->GetStars() );
1527  program.setAttribute( "fileSize" ,
1528  QString::number( pInfo->GetFilesize() ));
1529  program.setAttribute( "lastModified",
1531  program.setAttribute( "programFlags", pInfo->GetProgramFlags() );
1532  program.setAttribute( "hostname" , pInfo->GetHostname() );
1533 
1534  if (pInfo->GetOriginalAirDate().isValid())
1535  program.setAttribute(
1536  "airdate", pInfo->GetOriginalAirDate().toString());
1537 
1538  QDomText textNode = pDoc->createTextNode( pInfo->GetDescription() );
1539  program.appendChild( textNode );
1540 
1541  }
1542 
1543  if ( bIncChannel )
1544  {
1545  // Build Channel Child Element
1546 
1547  QDomElement channel = pDoc->createElement( "Channel" );
1548  program.appendChild( channel );
1549 
1550  FillChannelInfo( channel, pInfo, bDetails );
1551  }
1552 
1553  // Build Recording Child Element
1554 
1555  if ( pInfo->GetRecordingStatus() != rsUnknown )
1556  {
1557  QDomElement recording = pDoc->createElement( "Recording" );
1558  program.appendChild( recording );
1559 
1560  recording.setAttribute( "recStatus" ,
1561  pInfo->GetRecordingStatus() );
1562  recording.setAttribute( "recPriority" ,
1563  pInfo->GetRecordingPriority() );
1564  recording.setAttribute( "recStartTs" ,
1566  recording.setAttribute( "recEndTs" ,
1568 
1569  if (bDetails)
1570  {
1571  recording.setAttribute( "recordId" ,
1572  pInfo->GetRecordingRuleID() );
1573  recording.setAttribute( "recGroup" ,
1574  pInfo->GetRecordingGroup() );
1575  recording.setAttribute( "playGroup" ,
1576  pInfo->GetPlaybackGroup() );
1577  recording.setAttribute( "recType" ,
1578  pInfo->GetRecordingRuleType() );
1579  recording.setAttribute( "dupInType" ,
1580  pInfo->GetDuplicateCheckSource() );
1581  recording.setAttribute( "dupMethod" ,
1582  pInfo->GetDuplicateCheckMethod() );
1583  recording.setAttribute( "encoderId" ,
1584  pInfo->GetCardID() );
1585  const RecordingInfo ri(*pInfo);
1586  recording.setAttribute( "recProfile" ,
1588  //recording.setAttribute( "preRollSeconds", m_nPreRollSeconds );
1589  }
1590  }
1591 }
1592 
1594 //
1596 
1597 void HttpStatus::FillChannelInfo( QDomElement &channel,
1598  ProgramInfo *pInfo,
1599  bool bDetails /* = true */ )
1600 {
1601  if (pInfo)
1602  {
1603 /*
1604  QString sHostName = gCoreContext->GetHostName();
1605  QString sPort = gCoreContext->GetSettingOnHost( "BackendStatusPort",
1606  sHostName);
1607  QString sIconURL = QString( "http://%1:%2/getChannelIcon?ChanId=%3" )
1608  .arg( sHostName )
1609  .arg( sPort )
1610  .arg( pInfo->chanid );
1611 */
1612 
1613  channel.setAttribute( "chanId" , pInfo->GetChanID() );
1614  channel.setAttribute( "chanNum" , pInfo->GetChanNum());
1615  channel.setAttribute( "callSign" , pInfo->GetChannelSchedulingID());
1616  //channel.setAttribute( "iconURL" , sIconURL );
1617  channel.setAttribute( "channelName", pInfo->GetChannelName());
1618 
1619  if (bDetails)
1620  {
1621  channel.setAttribute( "chanFilters",
1622  pInfo->GetChannelPlaybackFilters() );
1623  channel.setAttribute( "sourceId" , pInfo->GetSourceID() );
1624  channel.setAttribute( "inputId" , pInfo->GetInputID() );
1625  channel.setAttribute( "commFree" ,
1626  (pInfo->IsCommercialFree()) ? 1 : 0 );
1627  }
1628  }
1629 }
1630 
1631 
1632 
1633 
1634 // vim:set shiftwidth=4 tabstop=4 expandtab: