MythTV  0.26-pre
httpstatus.cpp
Go to the documentation of this file.
00001 
00002 // Program Name: httpstatus.cpp
00003 //
00004 // Purpose - Html & XML status HttpServerExtension
00005 //
00006 // Created By  : David Blain                    Created On : Oct. 24, 2005
00007 // Modified By :                                Modified On:
00008 //
00010 
00011 // POSIX headers
00012 #include <unistd.h>
00013 
00014 // ANSI C headers
00015 #include <cmath>
00016 #include <cstdio>
00017 #include <cstdlib>
00018 
00019 // Qt headers
00020 #include <QTextStream>
00021 #include <QRegExp>
00022 #include <QLocale>
00023 
00024 // MythTV headers
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     // UTF-8 is the default, but good practice to specify it anyway
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");   // Otherwise locale default is used.
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     // Add Root Node.
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     // Add all encoders, if any
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             //encoder.setAttribute("lowOnFreeSpace", elink->isLowOnFreeSpace());
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     // Add upcoming shows
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     // Add known frontends
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     // Other backends
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     // Add Job Queue Entries
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     // Add Machine information
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     // drive space   ---------------------
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     // Make a temporary list to hold the per-filesystem elements so that the
00451     // total is always the first element.
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; // ignore dirID
00461         ++sit; // ignore blocksize
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     // load average ---------------------
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     // Guide Data ---------------------
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     // Add Miscellaneous information
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     // encoder information ---------------------
00654 
00655     QDomNode node = docElem.namedItem( "Encoders" );
00656 
00657     if (!node.isNull())
00658         PrintEncoderStatus( os, node.toElement() );
00659 
00660     // upcoming shows --------------------------
00661 
00662     node = docElem.namedItem( "Scheduled" );
00663 
00664     if (!node.isNull())
00665         PrintScheduled( os, node.toElement());
00666 
00667     // Frontends
00668 
00669     node = docElem.namedItem( "Frontends" );
00670 
00671     if (!node.isNull())
00672         PrintFrontends (os, node.toElement());
00673 
00674     // Backends
00675 
00676     node = docElem.namedItem( "Backends" );
00677 
00678     if (!node.isNull())
00679         PrintBackends (os, node.toElement());
00680 
00681     // Job Queue Entries -----------------------
00682 
00683     node = docElem.namedItem( "JobQueue" );
00684 
00685     if (!node.isNull())
00686         PrintJobQueue( os, node.toElement());
00687 
00688     // Machine information ---------------------
00689 
00690     node = docElem.namedItem( "MachineInfo" );
00691 
00692     if (!node.isNull())
00693         PrintMachineInfo( os, node.toElement());
00694 
00695     // Miscellaneous information ---------------
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                 // Display first Program Element listed under the encoder
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                         // Get Channel information
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                         // Get Recording Information (if any)
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     // Iterate through all scheduled programs
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 //                QDateTime recEndTs     = QDateTime::fromString( r.attribute( "recEndTs"  ,"" ), Qt::ISODate );
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                 // Build Time to recording start.
00919 
00920                 int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
00921 
00922                 //since we're not displaying seconds
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                     // Output HTML
00944 
00945                 os << "      <a href=\"#\">";
00946                 if (shortdateformat.indexOf("ddd") == -1) {
00947                     // If day-of-week not already present somewhere, prepend it.
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 << "&nbsp(<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 << "&nbsp(<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"   , "" );       //.replace(QRegExp("\""), "&quot;");
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     // load average ---------------------
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     // local drive space   ---------------------
01249     node = info.namedItem( "Storage" );
01250     QDomElement storage = node.toElement();
01251     node = storage.firstChild();
01252 
01253     // Loop once until we find id == "total".  This should be first, but a loop
01254     // separate from the per-filesystem details loop ensures total is first,
01255     // regardless.
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     // Loop again to handle per-filesystem details.
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     // Guide Info ---------------------
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     // Miscellaneous information
01464 
01465     QDomNodeList nodes = info.elementsByTagName("Information");
01466     uint count = nodes.count();
01467     if (count > 0)
01468     {
01469         QString display, linebreak;
01470         //QString name, value;
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             //name = e.attribute("name", "");
01485             //value = e.attribute("value", "");
01486 
01487             if (display.isEmpty())
01488                 continue;
01489 
01490             // Only include HTML line break if display value doesn't already
01491             // contain breaks.
01492             if ((display.contains("<p>", Qt::CaseInsensitive) > 0) ||
01493                 (display.contains("<br", Qt::CaseInsensitive) > 0))
01494             {
01495                 // matches <BR> or <br /
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 /* = true */,
01513                                  bool          bDetails    /* = true */)
01514 {
01515     if ((pDoc == NULL) || (pInfo == NULL))
01516         return;
01517 
01518     // Build Program Element
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         // Build Channel Child Element
01557 
01558         QDomElement channel = pDoc->createElement( "Channel" );
01559         program.appendChild( channel );
01560 
01561         FillChannelInfo( channel, pInfo, bDetails );
01562     }
01563 
01564     // Build Recording Child Element
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             //recording.setAttribute( "preRollSeconds", m_nPreRollSeconds );
01600         }
01601     }
01602 }
01603 
01605 //
01607 
01608 void HttpStatus::FillChannelInfo( QDomElement &channel,
01609                                   ProgramInfo *pInfo,
01610                                   bool         bDetails  /* = true */ )
01611 {
01612     if (pInfo)
01613     {
01614 /*
01615         QString sHostName = gCoreContext->GetHostName();
01616         QString sPort     = gCoreContext->GetSettingOnHost( "BackendStatusPort",
01617                                                         sHostName);
01618         QString sIconURL  = QString( "http://%1:%2/getChannelIcon?ChanId=%3" )
01619                                    .arg( sHostName )
01620                                    .arg( sPort )
01621                                    .arg( pInfo->chanid );
01622 */
01623 
01624         channel.setAttribute( "chanId"     , pInfo->GetChanID() );
01625         channel.setAttribute( "chanNum"    , pInfo->GetChanNum());
01626         channel.setAttribute( "callSign"   , pInfo->GetChannelSchedulingID());
01627         //channel.setAttribute( "iconURL"    , sIconURL           );
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 // vim:set shiftwidth=4 tabstop=4 expandtab:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends