00001
00002
00003
00004
00005
00006
00007
00008
00010
00011
00012 #include <unistd.h>
00013
00014
00015 #include <cmath>
00016 #include <cstdio>
00017 #include <cstdlib>
00018
00019
00020 #include <QTextStream>
00021 #include <QRegExp>
00022 #include <QLocale>
00023
00024
00025 #include "httpstatus.h"
00026
00027 #include "mythcorecontext.h"
00028 #include "mythversion.h"
00029 #include "mythdbcon.h"
00030 #include "compat.h"
00031 #include "mythconfig.h"
00032 #include "autoexpire.h"
00033 #include "tv.h"
00034 #include "encoderlink.h"
00035 #include "scheduler.h"
00036 #include "mainserver.h"
00037 #include "cardutil.h"
00038 #include "mythsystem.h"
00039 #include "exitcodes.h"
00040 #include "jobqueue.h"
00041 #include "upnp.h"
00042 #include <mythmiscutil.h>
00043
00045
00047
00048 HttpStatus::HttpStatus( QMap<int, EncoderLink *> *tvList, Scheduler *sched,
00049 AutoExpire *expirer, bool bIsMaster )
00050 : HttpServerExtension( "HttpStatus" , QString())
00051 {
00052 m_pEncoders = tvList;
00053 m_pSched = sched;
00054 m_pExpirer = expirer;
00055 m_bIsMaster = bIsMaster;
00056
00057 m_nPreRollSeconds = gCoreContext->GetNumSetting("RecordPreRoll", 0);
00058
00059 m_pMainServer = NULL;
00060 }
00061
00063
00065
00066 HttpStatus::~HttpStatus()
00067 {
00068 }
00069
00071
00073
00074 HttpStatusMethod HttpStatus::GetMethod( const QString &sURI )
00075 {
00076 if (sURI == "Status" ) return( HSM_GetStatusHTML );
00077 if (sURI == "GetStatusHTML" ) return( HSM_GetStatusHTML );
00078 if (sURI == "GetStatus" ) return( HSM_GetStatusXML );
00079 if (sURI == "xml" ) return( HSM_GetStatusXML );
00080
00081 return( HSM_Unknown );
00082 }
00083
00085
00087
00088 QStringList HttpStatus::GetBasePaths()
00089 {
00090 return QStringList( "/Status" );
00091 }
00092
00094
00096
00097 bool HttpStatus::ProcessRequest( HTTPRequest *pRequest )
00098 {
00099 try
00100 {
00101 if (pRequest)
00102 {
00103 if ((pRequest->m_sBaseUrl != "/Status" ) &&
00104 (pRequest->m_sResourceUrl != "/Status" ))
00105 {
00106 return( false );
00107 }
00108
00109 switch( GetMethod( pRequest->m_sMethod ))
00110 {
00111 case HSM_GetStatusXML : GetStatusXML ( pRequest ); return true;
00112 case HSM_GetStatusHTML : GetStatusHTML ( pRequest ); return true;
00113
00114 default:
00115 {
00116 pRequest->m_eResponseType = ResponseTypeHTML;
00117 pRequest->m_nResponseStatus = 200;
00118
00119 break;
00120 }
00121 }
00122 }
00123 }
00124 catch( ... )
00125 {
00126 LOG(VB_GENERAL, LOG_ERR,
00127 "HttpStatus::ProcessRequest() - Unexpected Exception");
00128 }
00129
00130 return( false );
00131 }
00132
00134
00136
00137 void HttpStatus::GetStatusXML( HTTPRequest *pRequest )
00138 {
00139 QDomDocument doc( "Status" );
00140
00141
00142 QDomProcessingInstruction encoding =
00143 doc.createProcessingInstruction("xml",
00144 "version=\"1.0\" encoding=\"UTF-8\"");
00145 doc.appendChild(encoding);
00146
00147 FillStatusXML( &doc );
00148
00149 pRequest->m_eResponseType = ResponseTypeXML;
00150 pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
00151
00152 QTextStream stream( &pRequest->m_response );
00153 stream.setCodec("UTF-8");
00154 stream << doc.toString();
00155 }
00156
00158
00160
00161 void HttpStatus::GetStatusHTML( HTTPRequest *pRequest )
00162 {
00163 pRequest->m_eResponseType = ResponseTypeHTML;
00164 pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
00165
00166 QDomDocument doc( "Status" );
00167
00168 FillStatusXML( &doc );
00169
00170 QTextStream stream( &pRequest->m_response );
00171 PrintStatus( stream, &doc );
00172 }
00173
00174 void HttpStatus::FillStatusXML( QDomDocument *pDoc )
00175 {
00176 QDateTime qdtNow = QDateTime::currentDateTime();
00177
00178
00179
00180 QDomElement root = pDoc->createElement("Status");
00181 pDoc->appendChild(root);
00182
00183 root.setAttribute("date" , MythDateTimeToString(qdtNow,
00184 kDateFull | kAddYear));
00185 root.setAttribute("time" , MythDateTimeToString(qdtNow, kTime));
00186 root.setAttribute("ISODate" , qdtNow.toString(Qt::ISODate) );
00187 root.setAttribute("version" , MYTH_BINARY_VERSION );
00188 root.setAttribute("protoVer", MYTH_PROTO_VERSION );
00189
00190
00191
00192 QDomElement encoders = pDoc->createElement("Encoders");
00193 root.appendChild(encoders);
00194
00195 int numencoders = 0;
00196 bool isLocal = true;
00197
00198 QMap<int, EncoderLink *>::Iterator iter = m_pEncoders->begin();
00199
00200 for (; iter != m_pEncoders->end(); ++iter)
00201 {
00202 EncoderLink *elink = *iter;
00203
00204 if (elink != NULL)
00205 {
00206 TVState state = elink->GetState();
00207 isLocal = elink->IsLocal();
00208
00209 QDomElement encoder = pDoc->createElement("Encoder");
00210 encoders.appendChild(encoder);
00211
00212 encoder.setAttribute("id" , elink->GetCardID() );
00213 encoder.setAttribute("local" , isLocal );
00214 encoder.setAttribute("connected" , elink->IsConnected() );
00215 encoder.setAttribute("state" , state );
00216 encoder.setAttribute("sleepstatus" , elink->GetSleepStatus() );
00217
00218
00219 if (isLocal)
00220 encoder.setAttribute("hostname", gCoreContext->GetHostName());
00221 else
00222 encoder.setAttribute("hostname", elink->GetHostName());
00223
00224 encoder.setAttribute("devlabel",
00225 CardUtil::GetDeviceLabel(elink->GetCardID()) );
00226
00227 if (elink->IsConnected())
00228 numencoders++;
00229
00230 switch (state)
00231 {
00232 case kState_WatchingLiveTV:
00233 case kState_RecordingOnly:
00234 case kState_WatchingRecording:
00235 {
00236 ProgramInfo *pInfo = elink->GetRecording();
00237
00238 if (pInfo)
00239 {
00240 FillProgramInfo(pDoc, encoder, pInfo);
00241 delete pInfo;
00242 }
00243
00244 break;
00245 }
00246
00247 default:
00248 break;
00249 }
00250 }
00251 }
00252
00253 encoders.setAttribute("count", numencoders);
00254
00255
00256
00257 QDomElement scheduled = pDoc->createElement("Scheduled");
00258 root.appendChild(scheduled);
00259
00260 RecList recordingList;
00261
00262 if (m_pSched)
00263 m_pSched->GetAllPending(recordingList);
00264
00265 unsigned int iNum = 10;
00266 unsigned int iNumRecordings = 0;
00267
00268 RecConstIter itProg = recordingList.begin();
00269 for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg)
00270 {
00271 if (((*itProg)->GetRecordingStatus() <= rsWillRecord) &&
00272 ((*itProg)->GetRecordingStartTime() >=
00273 QDateTime::currentDateTime()))
00274 {
00275 iNumRecordings++;
00276 FillProgramInfo(pDoc, scheduled, *itProg);
00277 }
00278 }
00279
00280 while (!recordingList.empty())
00281 {
00282 ProgramInfo *pginfo = recordingList.back();
00283 delete pginfo;
00284 recordingList.pop_back();
00285 }
00286
00287 scheduled.setAttribute("count", iNumRecordings);
00288
00289
00290
00291 QDomElement frontends = pDoc->createElement("Frontends");
00292 root.appendChild(frontends);
00293
00294 SSDPCacheEntries *fes = SSDP::Find(
00295 "urn:schemas-mythtv-org:service:MythFrontend:1");
00296 if (fes)
00297 {
00298 EntryMap map;
00299 fes->GetEntryMap(map);
00300 fes->Release();
00301 fes = NULL;
00302
00303 frontends.setAttribute( "count", map.size() );
00304 QMapIterator< QString, DeviceLocation * > i(map);
00305 while (i.hasNext())
00306 {
00307 i.next();
00308 QDomElement fe = pDoc->createElement("Frontend");
00309 frontends.appendChild(fe);
00310 QUrl url(i.value()->m_sLocation);
00311 fe.setAttribute("name", url.host());
00312 fe.setAttribute("url", url.toString(QUrl::RemovePath));
00313 i.value()->Release();
00314 }
00315 }
00316
00317
00318
00319 QDomElement backends = pDoc->createElement("Backends");
00320 root.appendChild(backends);
00321
00322 int numbes = 0;
00323 if (!gCoreContext->IsMasterBackend())
00324 {
00325 numbes++;
00326 QString masterhost = gCoreContext->GetMasterHostName();
00327 QString masterip = gCoreContext->GetSetting("MasterServerIP");
00328 QString masterport = gCoreContext->GetSettingOnHost("BackendStatusPort", masterhost, "6544");
00329
00330 QDomElement mbe = pDoc->createElement("Backend");
00331 backends.appendChild(mbe);
00332 mbe.setAttribute("type", "Master");
00333 mbe.setAttribute("name", masterhost);
00334 mbe.setAttribute("url" , masterip + ":" + masterport);
00335 }
00336
00337 SSDPCacheEntries *sbes = SSDP::Find(
00338 "urn:schemas-mythtv-org:device:SlaveMediaServer:1");
00339 if (sbes)
00340 {
00341
00342 QString ipaddress = QString();
00343 if (!UPnp::g_IPAddrList.isEmpty())
00344 ipaddress = UPnp::g_IPAddrList.at(0);
00345
00346 EntryMap map;
00347 sbes->GetEntryMap(map);
00348 sbes->Release();
00349 sbes = NULL;
00350
00351 QMapIterator< QString, DeviceLocation * > i(map);
00352 while (i.hasNext())
00353 {
00354 i.next();
00355 QUrl url(i.value()->m_sLocation);
00356 if (url.host() != ipaddress)
00357 {
00358 numbes++;
00359 QDomElement mbe = pDoc->createElement("Backend");
00360 backends.appendChild(mbe);
00361 mbe.setAttribute("type", "Slave");
00362 mbe.setAttribute("name", url.host());
00363 mbe.setAttribute("url" , url.toString(QUrl::RemovePath));
00364 }
00365 i.value()->Release();
00366 }
00367 }
00368
00369 backends.setAttribute("count", numbes);
00370
00371
00372
00373 QDomElement jobqueue = pDoc->createElement("JobQueue");
00374 root.appendChild(jobqueue);
00375
00376 QMap<int, JobQueueEntry> jobs;
00377 QMap<int, JobQueueEntry>::Iterator it;
00378
00379 JobQueue::GetJobsInQueue(jobs,
00380 JOB_LIST_NOT_DONE | JOB_LIST_ERROR |
00381 JOB_LIST_RECENT);
00382
00383 for (it = jobs.begin(); it != jobs.end(); ++it)
00384 {
00385 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
00386 if (!pginfo.GetChanID())
00387 continue;
00388
00389 QDomElement job = pDoc->createElement("Job");
00390 jobqueue.appendChild(job);
00391
00392 job.setAttribute("id" , (*it).id );
00393 job.setAttribute("chanId" , (*it).chanid );
00394 job.setAttribute("startTime" ,
00395 (*it).recstartts.toString(Qt::ISODate));
00396 job.setAttribute("startTs" , (*it).startts );
00397 job.setAttribute("insertTime",
00398 (*it).inserttime.toString(Qt::ISODate));
00399 job.setAttribute("type" , (*it).type );
00400 job.setAttribute("cmds" , (*it).cmds );
00401 job.setAttribute("flags" , (*it).flags );
00402 job.setAttribute("status" , (*it).status );
00403 job.setAttribute("statusTime",
00404 (*it).statustime.toString(Qt::ISODate));
00405 job.setAttribute("schedTime" ,
00406 (*it).schedruntime.toString(Qt::ISODate));
00407 job.setAttribute("args" , (*it).args );
00408
00409 if ((*it).hostname.isEmpty())
00410 job.setAttribute("hostname", QObject::tr("master"));
00411 else
00412 job.setAttribute("hostname",(*it).hostname);
00413
00414 QDomText textNode = pDoc->createTextNode((*it).comment);
00415 job.appendChild(textNode);
00416
00417 FillProgramInfo(pDoc, job, &pginfo);
00418 }
00419
00420 jobqueue.setAttribute( "count", jobs.size() );
00421
00422
00423
00424 QDomElement mInfo = pDoc->createElement("MachineInfo");
00425 QDomElement storage = pDoc->createElement("Storage" );
00426 QDomElement load = pDoc->createElement("Load" );
00427 QDomElement guide = pDoc->createElement("Guide" );
00428
00429 root.appendChild (mInfo );
00430 mInfo.appendChild(storage);
00431 mInfo.appendChild(load );
00432 mInfo.appendChild(guide );
00433
00434
00435
00436 QStringList strlist;
00437 QString dirs;
00438 QString hostname;
00439 QString directory;
00440 QString isLocalstr;
00441 QString fsID;
00442 QString ids;
00443 long long iTotal = -1, iUsed = -1, iAvail = -1;
00444
00445 if (m_pMainServer)
00446 m_pMainServer->BackendQueryDiskSpace(strlist, true, m_bIsMaster);
00447
00448 QDomElement total;
00449
00450
00451
00452 QList<QDomElement> fsXML;
00453 QStringList::const_iterator sit = strlist.begin();
00454 while (sit != strlist.end())
00455 {
00456 hostname = *(sit++);
00457 directory = *(sit++);
00458 isLocalstr = *(sit++);
00459 fsID = *(sit++);
00460 ++sit;
00461 ++sit;
00462 iTotal = (*(sit++)).toLongLong();
00463 iUsed = (*(sit++)).toLongLong();;
00464 iAvail = iTotal - iUsed;
00465
00466 if (fsID == "-2")
00467 fsID = "total";
00468
00469 QDomElement group = pDoc->createElement("Group");
00470
00471 group.setAttribute("id" , fsID );
00472 group.setAttribute("total", (int)(iTotal>>10) );
00473 group.setAttribute("used" , (int)(iUsed>>10) );
00474 group.setAttribute("free" , (int)(iAvail>>10) );
00475 group.setAttribute("dir" , directory );
00476
00477 if (fsID == "total")
00478 {
00479 long long iLiveTV = -1, iDeleted = -1, iExpirable = -1;
00480 MSqlQuery query(MSqlQuery::InitCon());
00481 query.prepare("SELECT SUM(filesize) FROM recorded "
00482 " WHERE recgroup = :RECGROUP;");
00483
00484 query.bindValue(":RECGROUP", "LiveTV");
00485 if (query.exec() && query.next())
00486 {
00487 iLiveTV = query.value(0).toLongLong();
00488 }
00489 query.bindValue(":RECGROUP", "Deleted");
00490 if (query.exec() && query.next())
00491 {
00492 iDeleted = query.value(0).toLongLong();
00493 }
00494 query.prepare("SELECT SUM(filesize) FROM recorded "
00495 " WHERE autoexpire = 1 "
00496 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
00497 if (query.exec() && query.next())
00498 {
00499 iExpirable = query.value(0).toLongLong();
00500 }
00501 group.setAttribute("livetv", (int)(iLiveTV>>20) );
00502 group.setAttribute("deleted", (int)(iDeleted>>20) );
00503 group.setAttribute("expirable", (int)(iExpirable>>20) );
00504 total = group;
00505 }
00506 else
00507 fsXML << group;
00508 }
00509
00510 storage.appendChild(total);
00511 int num_elements = fsXML.size();
00512 for (int fs_index = 0; fs_index < num_elements; fs_index++)
00513 {
00514 storage.appendChild(fsXML[fs_index]);
00515 }
00516
00517
00518
00519 double rgdAverages[3];
00520
00521 if (getloadavg(rgdAverages, 3) != -1)
00522 {
00523 load.setAttribute("avg1", rgdAverages[0]);
00524 load.setAttribute("avg2", rgdAverages[1]);
00525 load.setAttribute("avg3", rgdAverages[2]);
00526 }
00527
00528
00529
00530 QDateTime GuideDataThrough;
00531
00532 MSqlQuery query(MSqlQuery::InitCon());
00533 query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;");
00534
00535 if (query.exec() && query.next())
00536 {
00537 GuideDataThrough = QDateTime::fromString(
00538 query.value(0).toString(), Qt::ISODate);
00539 }
00540
00541 guide.setAttribute("start",
00542 gCoreContext->GetSetting("mythfilldatabaseLastRunStart"));
00543 guide.setAttribute("end",
00544 gCoreContext->GetSetting("mythfilldatabaseLastRunEnd"));
00545 guide.setAttribute("status",
00546 gCoreContext->GetSetting("mythfilldatabaseLastRunStatus"));
00547 if (gCoreContext->GetNumSetting("MythFillGrabberSuggestsTime", 0))
00548 {
00549 guide.setAttribute("next",
00550 gCoreContext->GetSetting("MythFillSuggestedRunTime"));
00551 }
00552
00553 if (!GuideDataThrough.isNull())
00554 {
00555 guide.setAttribute("guideThru",
00556 QDateTime(GuideDataThrough).toString(Qt::ISODate));
00557 guide.setAttribute("guideDays", qdtNow.daysTo(GuideDataThrough));
00558 }
00559
00560 QDomText dataDirectMessage =
00561 pDoc->createTextNode(gCoreContext->GetSetting("DataDirectMessage"));
00562 guide.appendChild(dataDirectMessage);
00563
00564
00565
00566 QString info_script = gCoreContext->GetSetting("MiscStatusScript");
00567 if ((!info_script.isEmpty()) && (info_script != "none"))
00568 {
00569 QDomElement misc = pDoc->createElement("Miscellaneous");
00570 root.appendChild(misc);
00571
00572 uint flags = kMSRunShell | kMSStdOut | kMSBuffered;
00573 MythSystem ms(info_script, flags);
00574 ms.Run(10);
00575 if (ms.Wait() != GENERIC_EXIT_OK)
00576 {
00577 LOG(VB_GENERAL, LOG_ERR,
00578 QString("Error running miscellaneous "
00579 "status information script: %1").arg(info_script));
00580 return;
00581 }
00582
00583 QByteArray input = ms.ReadAll();
00584
00585 QStringList output = QString(input).split('\n',
00586 QString::SkipEmptyParts);
00587
00588 QStringList::iterator iter;
00589 for (iter = output.begin(); iter != output.end(); ++iter)
00590 {
00591 QDomElement info = pDoc->createElement("Information");
00592
00593 QStringList list = (*iter).split("[]:[]");
00594 unsigned int size = list.size();
00595 unsigned int hasAttributes = 0;
00596
00597 if ((size > 0) && (!list[0].isEmpty()))
00598 {
00599 info.setAttribute("display", list[0]);
00600 hasAttributes++;
00601 }
00602 if ((size > 1) && (!list[1].isEmpty()))
00603 {
00604 info.setAttribute("name", list[1]);
00605 hasAttributes++;
00606 }
00607 if ((size > 2) && (!list[2].isEmpty()))
00608 {
00609 info.setAttribute("value", list[2]);
00610 hasAttributes++;
00611 }
00612
00613 if (hasAttributes > 0)
00614 misc.appendChild(info);
00615 }
00616 }
00617 }
00618
00620
00622
00623 void HttpStatus::PrintStatus( QTextStream &os, QDomDocument *pDoc )
00624 {
00625
00626 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d");
00627 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
00628
00629 os.setCodec("UTF-8");
00630
00631 QDateTime qdtNow = QDateTime::currentDateTime();
00632
00633 QDomElement docElem = pDoc->documentElement();
00634
00635 os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
00636 << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
00637 << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
00638 << " xml:lang=\"en\" lang=\"en\">\r\n"
00639 << "<head>\r\n"
00640 << " <meta http-equiv=\"Content-Type\""
00641 << "content=\"text/html; charset=UTF-8\" />\r\n"
00642 << " <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
00643 << " <title>MythTV Status - "
00644 << docElem.attribute( "date", qdtNow.toString(shortdateformat) )
00645 << " "
00646 << docElem.attribute( "time", qdtNow.toString(timeformat) ) << " - "
00647 << docElem.attribute( "version", MYTH_BINARY_VERSION ) << "</title>\r\n"
00648 << "</head>\r\n"
00649 << "<body bgcolor=\"#fff\">\r\n"
00650 << "<div class=\"status\">\r\n"
00651 << " <h1 class=\"status\">MythTV Status</h1>\r\n";
00652
00653
00654
00655 QDomNode node = docElem.namedItem( "Encoders" );
00656
00657 if (!node.isNull())
00658 PrintEncoderStatus( os, node.toElement() );
00659
00660
00661
00662 node = docElem.namedItem( "Scheduled" );
00663
00664 if (!node.isNull())
00665 PrintScheduled( os, node.toElement());
00666
00667
00668
00669 node = docElem.namedItem( "Frontends" );
00670
00671 if (!node.isNull())
00672 PrintFrontends (os, node.toElement());
00673
00674
00675
00676 node = docElem.namedItem( "Backends" );
00677
00678 if (!node.isNull())
00679 PrintBackends (os, node.toElement());
00680
00681
00682
00683 node = docElem.namedItem( "JobQueue" );
00684
00685 if (!node.isNull())
00686 PrintJobQueue( os, node.toElement());
00687
00688
00689
00690 node = docElem.namedItem( "MachineInfo" );
00691
00692 if (!node.isNull())
00693 PrintMachineInfo( os, node.toElement());
00694
00695
00696
00697 node = docElem.namedItem( "Miscellaneous" );
00698
00699 if (!node.isNull())
00700 PrintMiscellaneousInfo( os, node.toElement());
00701
00702 os << "\r\n</div>\r\n</body>\r\n</html>\r\n";
00703
00704 }
00705
00707
00709
00710 int HttpStatus::PrintEncoderStatus( QTextStream &os, QDomElement encoders )
00711 {
00712 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
00713 int nNumEncoders = 0;
00714
00715 if (encoders.isNull())
00716 return 0;
00717
00718 os << " <div class=\"content\">\r\n"
00719 << " <h2 class=\"status\">Encoder Status</h2>\r\n";
00720
00721 QDomNode node = encoders.firstChild();
00722
00723 while (!node.isNull())
00724 {
00725 QDomElement e = node.toElement();
00726
00727 if (!e.isNull())
00728 {
00729 if (e.tagName() == "Encoder")
00730 {
00731 QString sIsLocal = (e.attribute( "local" , "remote" )== "1")
00732 ? "local" : "remote";
00733 QString sCardId = e.attribute( "id" , "0" );
00734 QString sHostName = e.attribute( "hostname" , "Unknown");
00735 bool bConnected= e.attribute( "connected", "0" ).toInt();
00736
00737 bool bIsLowOnFreeSpace=e.attribute( "lowOnFreeSpace", "0").toInt();
00738
00739 QString sDevlabel = e.attribute( "devlabel", "[ UNKNOWN ]");
00740
00741 os << " Encoder " << sCardId << " " << sDevlabel
00742 << " is " << sIsLocal << " on " << sHostName;
00743
00744 if ((sIsLocal == "remote") && !bConnected)
00745 {
00746 SleepStatus sleepStatus =
00747 (SleepStatus) e.attribute("sleepstatus",
00748 QString((int)sStatus_Undefined)).toInt();
00749
00750 if (sleepStatus == sStatus_Asleep)
00751 os << " (currently asleep).<br />";
00752 else
00753 os << " (currently not connected).<br />";
00754
00755 node = node.nextSibling();
00756 continue;
00757 }
00758
00759 nNumEncoders++;
00760
00761 TVState encState = (TVState) e.attribute( "state", "0").toInt();
00762
00763 switch( encState )
00764 {
00765 case kState_WatchingLiveTV:
00766 os << " and is watching Live TV";
00767 break;
00768
00769 case kState_RecordingOnly:
00770 case kState_WatchingRecording:
00771 os << " and is recording";
00772 break;
00773
00774 default:
00775 os << " and is not recording.";
00776 break;
00777 }
00778
00779
00780
00781 QDomNode tmpNode = e.namedItem( "Program" );
00782
00783 if (!tmpNode.isNull())
00784 {
00785 QDomElement program = tmpNode.toElement();
00786
00787 if (!program.isNull())
00788 {
00789 os << " '" << program.attribute( "title", "Unknown" ) << "'";
00790
00791
00792
00793 tmpNode = program.namedItem( "Channel" );
00794
00795 if (!tmpNode.isNull())
00796 {
00797 QDomElement channel = tmpNode.toElement();
00798
00799 if (!channel.isNull())
00800 os << " on "
00801 << channel.attribute( "callSign", "unknown" );
00802 }
00803
00804
00805
00806 tmpNode = program.namedItem( "Recording" );
00807
00808 if (!tmpNode.isNull())
00809 {
00810 QDomElement recording = tmpNode.toElement();
00811
00812 if (!recording.isNull())
00813 {
00814 QDateTime endTs = QDateTime::fromString(
00815 recording.attribute( "recEndTs", "" ),
00816 Qt::ISODate );
00817
00818 os << ". This recording ";
00819 if (endTs < QDateTime::currentDateTime())
00820 os << "was ";
00821 else
00822 os << "is ";
00823
00824 os << "scheduled to end at "
00825 << endTs.toString(timeformat);
00826 }
00827 }
00828 }
00829
00830 os << ".";
00831 }
00832
00833 if (bIsLowOnFreeSpace)
00834 {
00835 os << " <strong>WARNING</strong>:"
00836 << " This backend is low on free disk space!";
00837 }
00838
00839 os << "<br />\r\n";
00840 }
00841 }
00842
00843 node = node.nextSibling();
00844 }
00845
00846 os << " </div>\r\n\r\n";
00847
00848 return( nNumEncoders );
00849 }
00850
00852
00854
00855 int HttpStatus::PrintScheduled( QTextStream &os, QDomElement scheduled )
00856 {
00857 QDateTime qdtNow = QDateTime::currentDateTime();
00858 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d");
00859 QString longdateformat = gCoreContext->GetSetting("DateFormat", "M/d/yyyy");
00860 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
00861
00862 if (scheduled.isNull())
00863 return( 0 );
00864
00865 int nNumRecordings= scheduled.attribute( "count", "0" ).toInt();
00866
00867 os << " <div class=\"content\">\r\n"
00868 << " <h2 class=\"status\">Schedule</h2>\r\n";
00869
00870 if (nNumRecordings == 0)
00871 {
00872 os << " There are no shows scheduled for recording.\r\n"
00873 << " </div>\r\n";
00874 return( 0 );
00875 }
00876
00877 os << " The next " << nNumRecordings << " show" << (nNumRecordings == 1 ? "" : "s" )
00878 << " that " << (nNumRecordings == 1 ? "is" : "are")
00879 << " scheduled for recording:\r\n";
00880
00881 os << " <div class=\"schedule\">\r\n";
00882
00883
00884
00885 QDomNode node = scheduled.firstChild();
00886
00887 while (!node.isNull())
00888 {
00889 QDomElement e = node.toElement();
00890
00891 if (!e.isNull())
00892 {
00893 QDomNode recNode = e.namedItem( "Recording" );
00894 QDomNode chanNode = e.namedItem( "Channel" );
00895
00896 if ((e.tagName() == "Program") && !recNode.isNull() && !chanNode.isNull())
00897 {
00898 QDomElement r = recNode.toElement();
00899 QDomElement c = chanNode.toElement();
00900
00901 QString sTitle = e.attribute( "title" , "" );
00902 QString sSubTitle = e.attribute( "subTitle", "" );
00903 QDateTime airDate = QDateTime::fromString( e.attribute( "airdate" ,"" ), Qt::ISODate );
00904 QDateTime startTs = QDateTime::fromString( e.attribute( "startTime" ,"" ), Qt::ISODate );
00905 QDateTime endTs = QDateTime::fromString( e.attribute( "endTime" ,"" ), Qt::ISODate );
00906 QDateTime recStartTs = QDateTime::fromString( r.attribute( "recStartTs","" ), Qt::ISODate );
00907
00908 int nPreRollSecs = r.attribute( "preRollSeconds", "0" ).toInt();
00909 int nEncoderId = r.attribute( "encoderId" , "0" ).toInt();
00910 QString sProfile = r.attribute( "recProfile" , "" );
00911 QString sChanName = c.attribute( "channelName" , "" );
00912 QString sDesc = "";
00913
00914 QDomText text = e.firstChild().toText();
00915 if (!text.isNull())
00916 sDesc = text.nodeValue();
00917
00918
00919
00920 int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
00921
00922
00923
00924 nTotalSecs -= 60;
00925
00926 int nTotalDays = nTotalSecs / 86400;
00927 int nTotalHours = (nTotalSecs / 3600)
00928 - (nTotalDays * 24);
00929 int nTotalMins = (nTotalSecs / 60) % 60;
00930
00931 QString sTimeToStart = "in";
00932
00933 sTimeToStart += QObject::tr(" %n day(s),", "", nTotalDays );
00934 sTimeToStart += QObject::tr(" %n hour(s) and", "", nTotalHours);
00935 sTimeToStart += QObject::tr(" %n minute(s)", "", nTotalMins);
00936
00937 if ( nTotalHours == 0 && nTotalMins == 0)
00938 sTimeToStart = QObject::tr("within one minute", "Recording starting");
00939
00940 if ( nTotalSecs < 0)
00941 sTimeToStart = QObject::tr("soon", "Recording starting");
00942
00943
00944
00945 os << " <a href=\"#\">";
00946 if (shortdateformat.indexOf("ddd") == -1) {
00947
00948 os << recStartTs.addSecs(-nPreRollSecs).toString("ddd")
00949 << " ";
00950 }
00951 os << recStartTs.addSecs(-nPreRollSecs).toString(shortdateformat) << " "
00952 << recStartTs.addSecs(-nPreRollSecs).toString(timeformat) << " - ";
00953
00954 if (nEncoderId > 0)
00955 os << "Encoder " << nEncoderId << " - ";
00956
00957 os << sChanName << " - " << sTitle << "<br />"
00958 << "<span><strong>" << sTitle << "</strong> ("
00959 << startTs.toString(timeformat) << "-"
00960 << endTs.toString(timeformat) << ")<br />";
00961
00962 if ( !sSubTitle.isEmpty())
00963 os << "<em>" << sSubTitle << "</em><br /><br />";
00964
00965 if ( airDate.isValid())
00966 os << "Orig. Airdate: "
00967 << airDate.toString(longdateformat)
00968 << "<br /><br />";
00969
00970 os << sDesc << "<br /><br />"
00971 << "This recording will start " << sTimeToStart
00972 << " using encoder " << nEncoderId << " with the '"
00973 << sProfile << "' profile.</span></a><hr />\r\n";
00974 }
00975 }
00976
00977 node = node.nextSibling();
00978 }
00979 os << " </div>\r\n";
00980 os << " </div>\r\n\r\n";
00981
00982 return( nNumRecordings );
00983 }
00984
00986
00988
00989 int HttpStatus::PrintFrontends( QTextStream &os, QDomElement frontends )
00990 {
00991 if (frontends.isNull())
00992 return( 0 );
00993
00994 int nNumFES= frontends.attribute( "count", "0" ).toInt();
00995
00996 if (nNumFES < 1)
00997 return( 0 );
00998
00999
01000 os << " <div class=\"content\">\r\n"
01001 << " <h2 class=\"status\">Frontends</h2>\r\n";
01002
01003 QDomNode node = frontends.firstChild();
01004 while (!node.isNull())
01005 {
01006 QDomElement e = node.toElement();
01007
01008 if (!e.isNull())
01009 {
01010 QString name = e.attribute( "name" , "" );
01011 QString url = e.attribute( "url" , "" );
01012 os << name << " (<a href=\"" << url << "\">Status page</a>)<br />";
01013 }
01014
01015 node = node.nextSibling();
01016 }
01017
01018 os << " </div>\r\n\r\n";
01019
01020 return nNumFES;
01021 }
01022
01024
01026
01027 int HttpStatus::PrintBackends( QTextStream &os, QDomElement backends )
01028 {
01029 if (backends.isNull())
01030 return( 0 );
01031
01032 int nNumBES= backends.attribute( "count", "0" ).toInt();
01033
01034 if (nNumBES < 1)
01035 return( 0 );
01036
01037
01038 os << " <div class=\"content\">\r\n"
01039 << " <h2 class=\"status\">Other Backends</h2>\r\n";
01040
01041 QDomNode node = backends.firstChild();
01042 while (!node.isNull())
01043 {
01044 QDomElement e = node.toElement();
01045
01046 if (!e.isNull())
01047 {
01048 QString type = e.attribute( "type", "" );
01049 QString name = e.attribute( "name" , "" );
01050 QString url = e.attribute( "url" , "" );
01051 os << type << ": " << name << " (<a href=\"" << url << "\">Status page</a>)<br />";
01052 }
01053
01054 node = node.nextSibling();
01055 }
01056
01057 os << " </div>\r\n\r\n";
01058
01059 return nNumBES;
01060 }
01061
01063
01065
01066 int HttpStatus::PrintJobQueue( QTextStream &os, QDomElement jobs )
01067 {
01068 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d");
01069 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
01070
01071 if (jobs.isNull())
01072 return( 0 );
01073
01074 int nNumJobs= jobs.attribute( "count", "0" ).toInt();
01075
01076 os << " <div class=\"content\">\r\n"
01077 << " <h2 class=\"status\">Job Queue</h2>\r\n";
01078
01079 if (nNumJobs != 0)
01080 {
01081 QString statusColor;
01082 QString jobColor;
01083 QString timeDateFormat;
01084
01085 timeDateFormat = gCoreContext->GetSetting("DateFormat", "ddd MMMM d") +
01086 ' ' + gCoreContext->GetSetting("TimeFormat", "h:mm AP");
01087
01088 os << " Jobs currently in Queue or recently ended:\r\n<br />"
01089 << " <div class=\"schedule\">\r\n";
01090
01091
01092 QDomNode node = jobs.firstChild();
01093
01094 while (!node.isNull())
01095 {
01096 QDomElement e = node.toElement();
01097
01098 if (!e.isNull())
01099 {
01100 QDomNode progNode = e.namedItem( "Program" );
01101
01102 if ((e.tagName() == "Job") && !progNode.isNull() )
01103 {
01104 QDomElement p = progNode.toElement();
01105
01106 QDomNode recNode = p.namedItem( "Recording" );
01107 QDomNode chanNode = p.namedItem( "Channel" );
01108
01109 QDomElement r = recNode.toElement();
01110 QDomElement c = chanNode.toElement();
01111
01112 int nType = e.attribute( "type" , "0" ).toInt();
01113 int nStatus = e.attribute( "status", "0" ).toInt();
01114
01115 switch( nStatus )
01116 {
01117 case JOB_ABORTED:
01118 statusColor = " class=\"jobaborted\"";
01119 jobColor = "";
01120 break;
01121
01122 case JOB_ERRORED:
01123 statusColor = " class=\"joberrored\"";
01124 jobColor = " class=\"joberrored\"";
01125 break;
01126
01127 case JOB_FINISHED:
01128 statusColor = " class=\"jobfinished\"";
01129 jobColor = " class=\"jobfinished\"";
01130 break;
01131
01132 case JOB_RUNNING:
01133 statusColor = " class=\"jobrunning\"";
01134 jobColor = " class=\"jobrunning\"";
01135 break;
01136
01137 default:
01138 statusColor = " class=\"jobqueued\"";
01139 jobColor = " class=\"jobqueued\"";
01140 break;
01141 }
01142
01143 QString sTitle = p.attribute( "title" , "" );
01144 QString sSubTitle = p.attribute( "subTitle", "" );
01145 QDateTime startTs = QDateTime::fromString( p.attribute( "startTime" ,"" ), Qt::ISODate );
01146 QDateTime endTs = QDateTime::fromString( p.attribute( "endTime" ,"" ), Qt::ISODate );
01147 QDateTime recStartTs = QDateTime::fromString( r.attribute( "recStartTs","" ), Qt::ISODate );
01148 QDateTime statusTime = QDateTime::fromString( e.attribute( "statusTime","" ), Qt::ISODate );
01149 QDateTime schedRunTime = QDateTime::fromString( e.attribute( "schedTime","" ), Qt::ISODate );
01150 QString sHostname = e.attribute( "hostname", "master" );
01151 QString sComment = "";
01152
01153 QDomText text = e.firstChild().toText();
01154 if (!text.isNull())
01155 sComment = text.nodeValue();
01156
01157 os << "<a href=\"javascript:void(0)\">"
01158 << recStartTs.toString("ddd") << " "
01159 << recStartTs.toString(shortdateformat) << " "
01160 << recStartTs.toString(timeformat) << " - "
01161 << sTitle << " - <font" << jobColor << ">"
01162 << JobQueue::JobText( nType ) << "</font><br />"
01163 << "<span><strong>" << sTitle << "</strong> ("
01164 << startTs.toString(timeformat) << "-"
01165 << endTs.toString(timeformat) << ")<br />";
01166
01167 if (!sSubTitle.isEmpty())
01168 os << "<em>" << sSubTitle << "</em><br /><br />";
01169
01170 os << "Job: " << JobQueue::JobText( nType ) << "<br />";
01171
01172 if (schedRunTime > QDateTime::currentDateTime())
01173 os << "Scheduled Run Time: "
01174 << schedRunTime.toString(timeDateFormat)
01175 << "<br />";
01176
01177 os << "Status: <font" << statusColor << ">"
01178 << JobQueue::StatusText( nStatus )
01179 << "</font><br />"
01180 << "Status Time: "
01181 << statusTime.toString(timeDateFormat)
01182 << "<br />";
01183
01184 if ( nStatus != JOB_QUEUED)
01185 os << "Host: " << sHostname << "<br />";
01186
01187 if (!sComment.isEmpty())
01188 os << "<br />Comments:<br />" << sComment << "<br />";
01189
01190 os << "</span></a><hr />\r\n";
01191 }
01192 }
01193
01194 node = node.nextSibling();
01195 }
01196 os << " </div>\r\n";
01197 }
01198 else
01199 os << " Job Queue is currently empty.\r\n\r\n";
01200
01201 os << " </div>\r\n\r\n ";
01202
01203 return( nNumJobs );
01204
01205 }
01206
01208
01210
01211 int HttpStatus::PrintMachineInfo( QTextStream &os, QDomElement info )
01212 {
01213 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d");
01214 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
01215 QString sRep;
01216
01217 if (info.isNull())
01218 return( 0 );
01219
01220 os << "<div class=\"content\">\r\n"
01221 << " <h2 class=\"status\">Machine Information</h2>\r\n";
01222
01223
01224
01225 QDomNode node = info.namedItem( "Load" );
01226
01227 if (!node.isNull())
01228 {
01229 QDomElement e = node.toElement();
01230
01231 if (!e.isNull())
01232 {
01233 double dAvg1 = e.attribute( "avg1" , "0" ).toDouble();
01234 double dAvg2 = e.attribute( "avg2" , "0" ).toDouble();
01235 double dAvg3 = e.attribute( "avg3" , "0" ).toDouble();
01236
01237 os << " <div class=\"loadstatus\">\r\n"
01238 << " This machine's load average:"
01239 << "\r\n <ul>\r\n <li>"
01240 << "1 Minute: " << dAvg1 << "</li>\r\n"
01241 << " <li>5 Minutes: " << dAvg2 << "</li>\r\n"
01242 << " <li>15 Minutes: " << dAvg3
01243 << "</li>\r\n </ul>\r\n"
01244 << " </div>\r\n";
01245 }
01246 }
01247
01248
01249 node = info.namedItem( "Storage" );
01250 QDomElement storage = node.toElement();
01251 node = storage.firstChild();
01252
01253
01254
01255
01256 while (!node.isNull())
01257 {
01258 QDomElement g = node.toElement();
01259
01260 if (!g.isNull() && g.tagName() == "Group")
01261 {
01262 QString id = g.attribute("id", "" );
01263
01264 if (id == "total")
01265 {
01266 int nFree = g.attribute("free" , "0" ).toInt();
01267 int nTotal = g.attribute("total", "0" ).toInt();
01268 int nUsed = g.attribute("used" , "0" ).toInt();
01269 int nLiveTV = g.attribute("livetv" , "0" ).toInt();
01270 int nDeleted = g.attribute("deleted", "0" ).toInt();
01271 int nExpirable = g.attribute("expirable" , "0" ).toInt();
01272 QString nDir = g.attribute("dir" , "" );
01273
01274 nDir.replace(QRegExp(","), ", ");
01275
01276 os << " Disk Usage Summary:<br />\r\n";
01277 os << " <ul>\r\n";
01278
01279 os << " <li>Total Disk Space:\r\n"
01280 << " <ul>\r\n";
01281 QLocale c(QLocale::C);
01282
01283 os << " <li>Total Space: ";
01284 sRep = c.toString(nTotal) + " MB";
01285 os << sRep << "</li>\r\n";
01286
01287 os << " <li>Space Used: ";
01288 sRep = c.toString(nUsed) + " MB";
01289 os << sRep << "</li>\r\n";
01290
01291 os << " <li>Space Free: ";
01292 sRep = c.toString(nFree) + " MB";
01293 os << sRep << "</li>\r\n";
01294
01295 if ((nLiveTV + nDeleted + nExpirable) > 0)
01296 {
01297 os << " <li>Space Available "
01298 "After Auto-expire: ";
01299 sRep = c.toString(nFree + nLiveTV +
01300 nDeleted + nExpirable) + " MB";
01301 os << sRep << "\r\n";
01302 os << " <ul>\r\n";
01303 os << " <li>Space Used by LiveTV: ";
01304 sRep = c.toString(nLiveTV) + " MB";
01305 os << sRep << "</li>\r\n";
01306 os << " <li>Space Used by "
01307 "Deleted Recordings: ";
01308 sRep = c.toString(nDeleted) + " MB";
01309 os << sRep << "</li>\r\n";
01310 os << " <li>Space Used by "
01311 "Auto-expirable Recordings: ";
01312 sRep = c.toString(nExpirable) + " MB";
01313 os << sRep << "</li>\r\n";
01314 os << " </ul>\r\n";
01315 os << " </li>\r\n";
01316 }
01317
01318 os << " </ul>\r\n"
01319 << " </li>\r\n";
01320
01321 os << " </ul>\r\n";
01322 break;
01323 }
01324 }
01325
01326 node = node.nextSibling();
01327 }
01328
01329
01330 node = storage.firstChild();
01331
01332 os << " Disk Usage Details:<br />\r\n";
01333 os << " <ul>\r\n";
01334
01335
01336 while (!node.isNull())
01337 {
01338 QDomElement g = node.toElement();
01339
01340 if (!g.isNull() && g.tagName() == "Group")
01341 {
01342 int nFree = g.attribute("free" , "0" ).toInt();
01343 int nTotal = g.attribute("total", "0" ).toInt();
01344 int nUsed = g.attribute("used" , "0" ).toInt();
01345 QString nDir = g.attribute("dir" , "" );
01346 QString id = g.attribute("id" , "" );
01347
01348 nDir.replace(QRegExp(","), ", ");
01349
01350
01351 if (id != "total")
01352 {
01353
01354 os << " <li>MythTV Drive #" << id << ":"
01355 << "\r\n"
01356 << " <ul>\r\n";
01357
01358 if (nDir.contains(','))
01359 os << " <li>Directories: ";
01360 else
01361 os << " <li>Directory: ";
01362
01363 os << nDir << "</li>\r\n";
01364
01365 QLocale c(QLocale::C);
01366
01367 os << " <li>Total Space: ";
01368 sRep = c.toString(nTotal) + " MB";
01369 os << sRep << "</li>\r\n";
01370
01371 os << " <li>Space Used: ";
01372 sRep = c.toString(nUsed) + " MB";
01373 os << sRep << "</li>\r\n";
01374
01375 os << " <li>Space Free: ";
01376 sRep = c.toString(nFree) + " MB";
01377 os << sRep << "</li>\r\n";
01378
01379 os << " </ul>\r\n"
01380 << " </li>\r\n";
01381 }
01382
01383 }
01384
01385 node = node.nextSibling();
01386 }
01387
01388 os << " </ul>\r\n";
01389
01390
01391
01392 node = info.namedItem( "Guide" );
01393
01394 if (!node.isNull())
01395 {
01396 QDomElement e = node.toElement();
01397
01398 if (!e.isNull())
01399 {
01400 QString datetimefmt = "yyyy-MM-dd hh:mm";
01401 int nDays = e.attribute( "guideDays", "0" ).toInt();
01402 QString sStart = e.attribute( "start" , "" );
01403 QString sEnd = e.attribute( "end" , "" );
01404 QString sStatus = e.attribute( "status" , "" );
01405 QDateTime next = QDateTime::fromString( e.attribute( "next" , "" ), Qt::ISODate);
01406 QString sNext = next.isNull() ? "" : next.toString(datetimefmt);
01407 QString sMsg = "";
01408
01409 QDateTime thru = QDateTime::fromString( e.attribute( "guideThru", "" ), Qt::ISODate);
01410
01411 QDomText text = e.firstChild().toText();
01412
01413 if (!text.isNull())
01414 sMsg = text.nodeValue();
01415
01416 os << " Last mythfilldatabase run started on " << sStart
01417 << " and ";
01418
01419 if (sEnd < sStart)
01420 os << "is ";
01421 else
01422 os << "ended on " << sEnd << ". ";
01423
01424 os << sStatus << "<br />\r\n";
01425
01426 if (!next.isNull() && sNext >= sStart)
01427 {
01428 os << " Suggested next mythfilldatabase run: "
01429 << sNext << ".<br />\r\n";
01430 }
01431
01432 if (!thru.isNull())
01433 {
01434 os << " There's guide data until "
01435 << QDateTime( thru ).toString(datetimefmt);
01436
01437 if (nDays > 0)
01438 os << " (" << nDays << " day" << (nDays == 1 ? "" : "s" ) << ")";
01439
01440 os << ".";
01441
01442 if (nDays <= 3)
01443 os << " <strong>WARNING</strong>: is mythfilldatabase running?";
01444 }
01445 else
01446 os << " There's <strong>no guide data</strong> available! "
01447 << "Have you run mythfilldatabase?";
01448
01449 if (!sMsg.isEmpty())
01450 os << "<br />\r\n DataDirect Status: " << sMsg;
01451 }
01452 }
01453 os << "\r\n </div>\r\n";
01454
01455 return( 1 );
01456 }
01457
01458 int HttpStatus::PrintMiscellaneousInfo( QTextStream &os, QDomElement info )
01459 {
01460 if (info.isNull())
01461 return( 0 );
01462
01463
01464
01465 QDomNodeList nodes = info.elementsByTagName("Information");
01466 uint count = nodes.count();
01467 if (count > 0)
01468 {
01469 QString display, linebreak;
01470
01471 os << "<div class=\"content\">\r\n"
01472 << " <h2 class=\"status\">Miscellaneous</h2>\r\n";
01473 for (unsigned int i = 0; i < count; i++)
01474 {
01475 QDomNode node = nodes.item(i);
01476 if (node.isNull())
01477 continue;
01478
01479 QDomElement e = node.toElement();
01480 if (e.isNull())
01481 continue;
01482
01483 display = e.attribute("display", "");
01484
01485
01486
01487 if (display.isEmpty())
01488 continue;
01489
01490
01491
01492 if ((display.contains("<p>", Qt::CaseInsensitive) > 0) ||
01493 (display.contains("<br", Qt::CaseInsensitive) > 0))
01494 {
01495
01496 linebreak = "\r\n";
01497 }
01498 else
01499 linebreak = "<br />\r\n";
01500
01501 os << " " << display << linebreak;
01502 }
01503 os << "</div>\r\n";
01504 }
01505
01506 return( 1 );
01507 }
01508
01509 void HttpStatus::FillProgramInfo(QDomDocument *pDoc,
01510 QDomNode &node,
01511 ProgramInfo *pInfo,
01512 bool bIncChannel ,
01513 bool bDetails )
01514 {
01515 if ((pDoc == NULL) || (pInfo == NULL))
01516 return;
01517
01518
01519
01520 QDomElement program = pDoc->createElement( "Program" );
01521 node.appendChild( program );
01522
01523 program.setAttribute( "startTime" ,
01524 pInfo->GetScheduledStartTime(ISODate));
01525 program.setAttribute( "endTime" , pInfo->GetScheduledEndTime(ISODate));
01526 program.setAttribute( "title" , pInfo->GetTitle() );
01527 program.setAttribute( "subTitle" , pInfo->GetSubtitle());
01528 program.setAttribute( "category" , pInfo->GetCategory());
01529 program.setAttribute( "catType" , pInfo->GetCategoryType());
01530 program.setAttribute( "repeat" , pInfo->IsRepeat() );
01531
01532 if (bDetails)
01533 {
01534
01535 program.setAttribute( "seriesId" , pInfo->GetSeriesID() );
01536 program.setAttribute( "programId" , pInfo->GetProgramID() );
01537 program.setAttribute( "stars" , pInfo->GetStars() );
01538 program.setAttribute( "fileSize" ,
01539 QString::number( pInfo->GetFilesize() ));
01540 program.setAttribute( "lastModified",
01541 pInfo->GetLastModifiedTime(ISODate) );
01542 program.setAttribute( "programFlags", pInfo->GetProgramFlags() );
01543 program.setAttribute( "hostname" , pInfo->GetHostname() );
01544
01545 if (pInfo->GetOriginalAirDate().isValid())
01546 program.setAttribute( "airdate" , pInfo->GetOriginalAirDate()
01547 .toString(Qt::ISODate) );
01548
01549 QDomText textNode = pDoc->createTextNode( pInfo->GetDescription() );
01550 program.appendChild( textNode );
01551
01552 }
01553
01554 if ( bIncChannel )
01555 {
01556
01557
01558 QDomElement channel = pDoc->createElement( "Channel" );
01559 program.appendChild( channel );
01560
01561 FillChannelInfo( channel, pInfo, bDetails );
01562 }
01563
01564
01565
01566 if ( pInfo->GetRecordingStatus() != rsUnknown )
01567 {
01568 QDomElement recording = pDoc->createElement( "Recording" );
01569 program.appendChild( recording );
01570
01571 recording.setAttribute( "recStatus" ,
01572 pInfo->GetRecordingStatus() );
01573 recording.setAttribute( "recPriority" ,
01574 pInfo->GetRecordingPriority() );
01575 recording.setAttribute( "recStartTs" ,
01576 pInfo->GetRecordingStartTime(ISODate) );
01577 recording.setAttribute( "recEndTs" ,
01578 pInfo->GetRecordingEndTime(ISODate) );
01579
01580 if (bDetails)
01581 {
01582 recording.setAttribute( "recordId" ,
01583 pInfo->GetRecordingRuleID() );
01584 recording.setAttribute( "recGroup" ,
01585 pInfo->GetRecordingGroup() );
01586 recording.setAttribute( "playGroup" ,
01587 pInfo->GetPlaybackGroup() );
01588 recording.setAttribute( "recType" ,
01589 pInfo->GetRecordingRuleType() );
01590 recording.setAttribute( "dupInType" ,
01591 pInfo->GetDuplicateCheckSource() );
01592 recording.setAttribute( "dupMethod" ,
01593 pInfo->GetDuplicateCheckMethod() );
01594 recording.setAttribute( "encoderId" ,
01595 pInfo->GetCardID() );
01596 const RecordingInfo ri(*pInfo);
01597 recording.setAttribute( "recProfile" ,
01598 ri.GetProgramRecordingProfile());
01599
01600 }
01601 }
01602 }
01603
01605
01607
01608 void HttpStatus::FillChannelInfo( QDomElement &channel,
01609 ProgramInfo *pInfo,
01610 bool bDetails )
01611 {
01612 if (pInfo)
01613 {
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 channel.setAttribute( "chanId" , pInfo->GetChanID() );
01625 channel.setAttribute( "chanNum" , pInfo->GetChanNum());
01626 channel.setAttribute( "callSign" , pInfo->GetChannelSchedulingID());
01627
01628 channel.setAttribute( "channelName", pInfo->GetChannelName());
01629
01630 if (bDetails)
01631 {
01632 channel.setAttribute( "chanFilters",
01633 pInfo->GetChannelPlaybackFilters() );
01634 channel.setAttribute( "sourceId" , pInfo->GetSourceID() );
01635 channel.setAttribute( "inputId" , pInfo->GetInputID() );
01636 channel.setAttribute( "commFree" ,
01637 (pInfo->IsCommercialFree()) ? 1 : 0 );
01638 }
01639 }
01640 }
01641
01642
01643
01644
01645