Files
neutrino/src/nhttpd/tuxboxapi/controlapi.cpp

3381 lines
106 KiB
C++

//=============================================================================
// NHTTPD
// Neutrino ControlAPI
//=============================================================================
#include <config.h>
// C
#include <stdio.h>
#include <stdint.h>
#include <cctype>
// C++
#include <string>
#include <fstream>
#include <map>
// system
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vfs.h> // for statfs
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <unistd.h>
#include <dirent.h>
// tuxbox
#include <global.h>
#include <neutrinoMessages.h>
#include <zapit/client/zapittools.h>
#include <zapit/zapit.h>
#include <eitd/sectionsd.h>
#include <configfile.h>
#include <system/configure_network.h>
#include <cs_api.h>
#include <global.h>
#include <gui/plugins.h>//for relodplugins
#include <neutrino.h>
#include <driver/screenshot.h>
#include <gui/rc_lock.h>
#include <rcsim.h>
#include <driver/pictureviewer/pictureviewer.h>
extern CPictureViewer *g_PicViewer;
// yhttpd
#include <yhttpd.h>
#include <ytypes_globals.h>
#include <ylogging.h>
#include <helper.h>
// nhttpd
#include "neutrinoapi.h"
#include "controlapi.h"
#include <video.h>
#include <zapit/femanager.h>
extern cVideo * videoDecoder;
extern CPlugins *g_PluginList;//for relodplugins
extern CBouquetManager *g_bouquetManager;
#define EVENTDEV "/dev/input/input0"
//-----------------------------------------------------------------------------
//=============================================================================
// Initialization of static variables
//=============================================================================
std::string CControlAPI::PLUGIN_DIRS[PLUGIN_DIR_COUNT];
//=============================================================================
// constructor und destructor
//=============================================================================
CControlAPI::CControlAPI(CNeutrinoAPI *_NeutrinoAPI)
{
NeutrinoAPI = _NeutrinoAPI;
}
//-----------------------------------------------------------------------------
void CControlAPI::init(CyhookHandler *hh)
{
if(PLUGIN_DIRS[0].empty())
{ // given in nhttpd.conf
PLUGIN_DIRS[0]=PLUGIN_DIRS[1]=hh->WebserverConfigList["WebsiteMain.override_directory"];
PLUGIN_DIRS[1].append("/scripts");
PLUGIN_DIRS[2]=PLUGIN_DIRS[3]=hh->WebserverConfigList["WebsiteMain.directory"];
PLUGIN_DIRS[3].append("/scripts");
PLUGIN_DIRS[4]=GAMESDIR;
PLUGIN_DIRS[5]=g_settings.plugin_hdd_dir;
PLUGIN_DIRS[6]=PLUGINDIR_MNT;
PLUGIN_DIRS[7]=PLUGINDIR_VAR;
PLUGIN_DIRS[8]=PLUGINDIR;
}
}
//=============================================================================
// Hooks!
//=============================================================================
//-----------------------------------------------------------------------------
THandleStatus CControlAPI::Hook_PrepareResponse(CyhookHandler *hh)
{
init(hh);
if(hh->UrlData["path"] == "/control/"
|| hh->UrlData["path"] == "/cgi-bin/"
|| hh->UrlData["path"] == "/fb/"
)
return HANDLED_READY;
else
return HANDLED_NONE;
}
//-----------------------------------------------------------------------------
// HOOK: response_hook Handler
// This is the main dispatcher for this module
//-----------------------------------------------------------------------------
THandleStatus CControlAPI::Hook_SendResponse(CyhookHandler *hh)
{
hh->status = HANDLED_NONE;
// log_level_printfX(4,"CControlAPI hook start url:%s\n",hh->UrlData["url"].c_str());
init(hh);
if(hh->UrlData["path"] == "/control/"
|| hh->UrlData["path"] == "/cgi-bin/")
Execute(hh);
if(hh->UrlData["path"] == "/fb/") // fb-compatibility for timer-calls
compatibility_Timer(hh);
// log_level_printfX(4,"CControlAPI hook ende status:%d\n",(int)hh->status);
// log_level_printfX(5,"CControlAPI hook result:%s\n",hh->yresult.c_str());
return hh->status;
}
//=============================================================================
//-------------------------------------------------------------------------
// timer compatibility
// do add/modify/remove and Return (redirect) Timerlist
//-------------------------------------------------------------------------
void CControlAPI::compatibility_Timer(CyhookHandler *hh)
{
log_level_printf(4,"CControlAPI Compatibility Timer Start url:%s\n",hh->UrlData["url"].c_str());
if(NeutrinoAPI->Timerd->isTimerdAvailable() && !hh->ParamList.empty() )
{
if(hh->ParamList["action"] == "remove")
{
unsigned removeId = atoi(hh->ParamList["id"].c_str());
NeutrinoAPI->Timerd->removeTimerEvent(removeId);
}
else if(hh->ParamList["action"] == "modify")
doModifyTimer(hh);
else if(hh->ParamList["action"] == "new")
doNewTimer(hh);
}
hh->SendRedirect("/Y_Timer_List.yhtm");
}
//=============================================================================
// Main Dispatcher / Call definitions
//=============================================================================
const CControlAPI::TyCgiCall CControlAPI::yCgiCallList[]=
{
// channel & bouquet & epg & zapping handling
{"getservicesxml", &CControlAPI::GetServicesxmlCGI, ""},
{"getbouquetsxml", &CControlAPI::GetBouquetsxmlCGI, ""},
{"getubouquetsxml", &CControlAPI::GetUBouquetsxmlCGI, ""},
{"channellist", &CControlAPI::ChannellistCGI, "text/plain"},
{"logolist", &CControlAPI::LogolistCGI, "text/plain"},
{"getbouquet", &CControlAPI::GetBouquetCGI, "+xml"},
{"getbouquets", &CControlAPI::GetBouquetsCGI, "+xml"},
{"getmode", &CControlAPI::GetModeCGI, "text/plain"},
{"setmode", &CControlAPI::SetModeCGI, "text/plain"},
{"epgsearchxml", &CControlAPI::EpgSearchXMLCGI, ""},
{"epgsearch", &CControlAPI::EpgSearchCGI, ""},
{"epg", &CControlAPI::EpgCGI, ""},
{"zapto", &CControlAPI::ZaptoCGI, "text/plain"},
{"signal", &CControlAPI::SignalInfoCGI, "text/plain"},
{"getonidsid", &CControlAPI::GetChannel_IDCGI, "text/plain"},
{"currenttpchannels", &CControlAPI::GetTPChannel_IDCGI, "text/plain"},
// boxcontrol - system
{"standby", &CControlAPI::StandbyCGI, "text/plain"},
{"shutdown", &CControlAPI::ShutdownCGI, "text/plain"},
{"reboot", &CControlAPI::RebootCGI, "text/plain"},
{"getdate", &CControlAPI::GetDateCGI, "text/plain"},
{"gettime", &CControlAPI::GetTimeCGI, "text/plain"},
{"info", &CControlAPI::InfoCGI, "text/plain"},
{"version", &CControlAPI::VersionCGI, ""},
{"reloadsetup", &CControlAPI::ReloadNeutrinoSetupCGI, ""},
{"reloadplugins", &CControlAPI::ReloadPluginsCGI, ""},
{"reloadchannels", &CControlAPI::ReloadChannelsCGI, ""},
{"screenshot", &CControlAPI::ScreenshotCGI, ""},
// boxcontrol - devices
{"volume", &CControlAPI::VolumeCGI, "text/plain"},
{"lcd", &CControlAPI::LCDAction, "text/plain"},
{"system", &CControlAPI::SystemCGI, "text/plain"},
{"message", &CControlAPI::MessageCGI, "text/plain"},
{"rc", &CControlAPI::RCCGI, "text/plain"},
{"rcem", &CControlAPI::RCEmCGI, "text/plain"},
// Start skripts, plugins
{"startplugin", &CControlAPI::StartPluginCGI, "text/plain"},
{"exec", &CControlAPI::ExecCGI, "text/plain"},
{"yweb", &CControlAPI::YWebCGI, "text/plain"},
// video & Audio handling
{"aspectratio", &CControlAPI::AspectRatioCGI, "text/plain"},
{"videoformat", &CControlAPI::VideoFormatCGI, "text/plain"},
{"videooutput", &CControlAPI::VideoOutputCGI, "text/plain"},
{"vcroutput", &CControlAPI::VCROutputCGI, "text/plain"},
{"scartmode", &CControlAPI::ScartModeCGI, "text/plain"},
{"audio", &CControlAPI::AudioCGI, "text/plain"},
{"crypt", &CControlAPI::CryptCGI, "text/plain"},
// timer
{"timer", &CControlAPI::TimerCGI, "text/plain"},
// bouquet editing
{"setbouquet", &CControlAPI::setBouquetCGI, "text/plain"},
{"savebouquet", &CControlAPI::saveBouquetCGI, "text/plain"},
{"movebouquet", &CControlAPI::moveBouquetCGI, "text/plain"},
{"deletebouquet", &CControlAPI::deleteBouquetCGI, "text/plain"},
{"addbouquet", &CControlAPI::addBouquetCGI, "text/plain"},
{"renamebouquet", &CControlAPI::renameBouquetCGI, "text/plain"},
{"changebouquet", &CControlAPI::changeBouquetCGI, "text/plain"},
{"updatebouquet", &CControlAPI::updateBouquetCGI, "text/plain"},
// utils
{"build_live_url", &CControlAPI::build_live_url, ""},
{"get_logo", &CControlAPI::logoCGI, "text/plain"},
// settings
{"config", &CControlAPI::ConfigCGI, "text/plain"},
// filehandling
{"file", &CControlAPI::FileCGI, "+xml"},
{"statfs", &CControlAPI::StatfsCGI, "+xml"},
{"getdir", &CControlAPI::getDirCGI, "+xml"}
};
//-----------------------------------------------------------------------------
// Main Dispatcher
//-----------------------------------------------------------------------------
void CControlAPI::Execute(CyhookHandler *hh)
{
int index = -1;
std::string filename = hh->UrlData["filename"];
log_level_printf(4,"ControlAPI.Execute filename:(%s)\n",filename.c_str());
// tolower(filename)
for(unsigned int i = 0; i < filename.length(); i++)
filename[i] = tolower(filename[i]);
// debugging informations
if(CLogging::getInstance()->getDebug())
{
dprintf("Execute CGI : %s\n",filename.c_str());
for(CStringList::iterator it = hh->ParamList.begin() ;
it != hh->ParamList.end() ; ++it)
dprintf(" Parameter %s : %s\n",it->first.c_str(), it->second.c_str());
}
// get function index
for(unsigned int i = 0; i < (sizeof(yCgiCallList)/sizeof(yCgiCallList[0])); i++)
if (filename == yCgiCallList[i].func_name)
{
index = i;
break;
}
if(index == -1) // function not found
{
hh->SetError(HTTP_NOT_IMPLEMENTED, HANDLED_NOT_IMPLEMENTED);
return;
}
// send header
else if(std::string(yCgiCallList[index].mime_type).empty()) // decide in function
;
else if(std::string(yCgiCallList[index].mime_type) == "+xml") // Parameter xml?
if (hh->getOutType() == xml)
hh->SetHeader(HTTP_OK, "text/xml; charset=UTF-8");
else
hh->SetHeader(HTTP_OK, "text/html; charset=UTF-8");
else
hh->SetHeader(HTTP_OK, yCgiCallList[index].mime_type);
// response
hh->status = HANDLED_READY;
if (hh->Method == M_HEAD) // HEAD or function call
return;
else
{
(this->*yCgiCallList[index].pfunc)(hh);
return;
}
}
//=============================================================================
// CGI Functions
// CyhookHandler contains input/output abstractions
//=============================================================================
void CControlAPI::TimerCGI(CyhookHandler *hh)
{
if (NeutrinoAPI->Timerd->isTimerdAvailable())
{
if (!hh->ParamList.empty() && hh->ParamList["format"].empty())
{
if (hh->ParamList["action"] == "new")
doNewTimer(hh);
else if (hh->ParamList["action"] == "modify")
doModifyTimer(hh);
else if (hh->ParamList["action"] == "remove")
{
unsigned removeId = atoi(hh->ParamList["id"].c_str());
NeutrinoAPI->Timerd->removeTimerEvent(removeId);
hh->SendOk();
}
else if(!hh->ParamList["get"].empty())
{
int pre=0,post=0;
NeutrinoAPI->Timerd->getRecordingSafety(pre,post);
if(hh->ParamList["get"] == "pre")
hh->printf("%d\n", pre);
else if(hh->ParamList["get"] == "post")
hh->printf("%d\n", post);
else
hh->SendError();
}
}
else {
if (hh->getOutType() == xml)
SendTimersXML(hh);
else
SendTimers(hh);
}
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::SetModeCGI(CyhookHandler *hh)
{
if (!(hh->ParamList.empty()))
{
if (hh->ParamList["1"] == "status") // display recoding status
{
if (NeutrinoAPI->Zapit->isRecordModeActive())
hh->WriteLn("on");
else
hh->WriteLn("off");
return;
}
if (hh->ParamList["1"] == "radio") // switch to radio mode
{
if(CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_standby){
int mode = NeutrinoMessages::mode_radio;
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::CHANGEMODE, CEventServer::INITID_HTTPD, (void *)&mode,sizeof(int));
sleep(1);
NeutrinoAPI->UpdateBouquets();
}else{
extern CRemoteControl * g_RemoteControl;
g_RemoteControl->radioMode();
}
}
else if (hh->ParamList["1"] == "tv") // switch to tv mode
{
if(CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_standby){
int mode = NeutrinoMessages::mode_tv;
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::CHANGEMODE, CEventServer::INITID_HTTPD, (void *)&mode,sizeof(int));
sleep(1);
NeutrinoAPI->UpdateBouquets();
}else{
extern CRemoteControl * g_RemoteControl;
g_RemoteControl->tvMode();
}
}
else if (hh->ParamList["record"] == "start") // start record mode
{
if(hh->ParamList["stopplayback"] == "true")
NeutrinoAPI->Zapit->stopPlayBack();
NeutrinoAPI->Sectionsd->setPauseScanning(true);
NeutrinoAPI->Zapit->setRecordMode(true);
}
else if (hh->ParamList["record"] == "stop") // stop record mode
{
NeutrinoAPI->Zapit->setRecordMode(false);
NeutrinoAPI->Sectionsd->setPauseScanning(false);
if (!NeutrinoAPI->Zapit->isPlayBackActive())
NeutrinoAPI->Zapit->startPlayBack();
}
hh->SendOk();
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::GetModeCGI(CyhookHandler *hh)
{
hh->outStart();
std::string result = "";
int mode = CNeutrinoApp::getInstance()->getMode();
if (mode == NeutrinoMessages::mode_tv)
result = "tv";
else if (mode == NeutrinoMessages::mode_radio)
result = "radio";
else if (mode == NeutrinoMessages::mode_scart)
result = "scart";
else if (mode == NeutrinoMessages::mode_standby)
result = "standby";
else if (mode == NeutrinoMessages::mode_audio)
result = "audio";
else if (mode == NeutrinoMessages::mode_pic)
result = "pic";
else if (mode == NeutrinoMessages::mode_ts)
result = "ts";
else if (mode == NeutrinoMessages::mode_webtv)
result = "webtv";
else if (mode == NeutrinoMessages::mode_upnp)
result = "upnp";
else
result = "unknown";
if (hh->getOutType() != plain)
{
result = hh->outPair("mode", result, false);
result = hh->outObject("getmode", result);
}
hh->SendResult(result);
}
//-----------------------------------------------------------------------------
void CControlAPI::ExecCGI(CyhookHandler *hh)
{
std::string script, result;
if (!hh->ParamList.empty() )
{
script = hh->ParamList["1"];
unsigned int len = hh->ParamList.size();
for(unsigned int y=2; y<=len; y++)
if(!hh->ParamList[itoa(y)].empty())
{
script += " ";
script += hh->ParamList[itoa(y)];
}
result = yExecuteScript(script);
}
else
{
log_level_printf(0, "[%s] no script given\n", __func__);
result = "error";
}
if (result == "error")
hh->SetError(HTTP_NOT_FOUND);
else
hh->WriteLn(result);
}
//-----------------------------------------------------------------------------
void CControlAPI::SystemCGI(CyhookHandler *hh)
{
if (!(hh->ParamList.empty()))
{
//FIXME: No system information until now
hh->SendOk();
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::StandbyCGI(CyhookHandler *hh)
{
if (!(hh->ParamList.empty()))
{
bool CEC_HDMI_off = false;
if (!(hh->ParamList["cec"].empty())){
if(hh->ParamList["cec"]=="off"){
CEC_HDMI_off = true;
}
}
if (hh->ParamList["1"] == "on") // standby mode on
{
//dont use CEC with standbyoff (TV off) --- use: control/standby?off&cec=off
if(g_settings.hdmi_cec_standby && CEC_HDMI_off){
videoDecoder->SetCECAutoStandby(0);
}
if(CNeutrinoApp::getInstance()->getMode() != 4)
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::STANDBY_ON, CEventServer::INITID_HTTPD);
hh->SendOk();
if(g_settings.hdmi_cec_standby && CEC_HDMI_off){//dont use CEC with standbyoff (TV off)
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::EVT_HDMI_CEC_STANDBY, CEventServer::INITID_HTTPD);
}
}
else if (hh->ParamList["1"] == "off")// standby mode off
{
//dont use CEC with with view on (TV on) --- use: control/standby?off&cec=off
if(g_settings.hdmi_cec_view_on && CEC_HDMI_off){
videoDecoder->SetCECAutoView(0);
}
NeutrinoAPI->Zapit->setStandby(false);
if(CNeutrinoApp::getInstance()->getMode() == 4)
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::STANDBY_OFF, CEventServer::INITID_HTTPD);
hh->SendOk();
if(g_settings.hdmi_cec_view_on && CEC_HDMI_off){//dont use CEC with view on (TV on)
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::EVT_HDMI_CEC_VIEW_ON, CEventServer::INITID_HTTPD);
}
}
else
hh->SendError();
}
else
if(CNeutrinoApp::getInstance()->getMode() == 4)//mode_standby = 4
hh->WriteLn("on");
else
hh->WriteLn("off");
}
//-----------------------------------------------------------------------------
void CControlAPI::RCCGI(CyhookHandler *hh)
{
bool locked = CRCLock::getInstance()->isLocked();
if (hh->ParamList.empty() || hh->ParamList["1"] == "status")
{
if (locked)
hh->WriteLn("off");
else
hh->WriteLn("on");
}
else
{
if (hh->ParamList["1"] == "lock")
{
if (!locked)
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::LOCK_RC, CEventServer::INITID_HTTPD);
}
else if (hh->ParamList["1"] == "unlock")
{
if (locked)
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::UNLOCK_RC, CEventServer::INITID_HTTPD);
}
else
{
hh->SendError();
return;
}
hh->SendOk();
}
}
//-----------------------------------------------------------------------------
// Get actual Date
// security: strftime has buffer-overflow limit. ok!
//-----------------------------------------------------------------------------
void CControlAPI::GetDateCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty())
{
//paramlos
char *timestr = new char[50];
struct timeb tm;
ftime(&tm);
strftime(timestr, 20, "%d.%m.%Y\n", localtime(&tm.time) );
hh->Write(timestr);
delete[] timestr;
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
// Get actual Time
// security: strftime has buffer-overflow limit. ok!
//-----------------------------------------------------------------------------
void CControlAPI::GetTimeCGI(CyhookHandler *hh)
{
time_t now = time(NULL);
if (hh->ParamList.empty())
{
//paramlos
char *timestr = new char[50];
struct tm *tm = localtime(&now);
strftime(timestr, 20, "%H:%M:%S\n", tm );
hh->Write(timestr);
delete[] timestr;
}
else if (hh->ParamList["1"].compare("rawtime") == 0)
hh->printf("%ld\n",now);
else
hh->SendError();
}
//-----------------------------------------------------------------------------
// send services.xml
void CControlAPI::GetServicesxmlCGI(CyhookHandler *hh)
{
hh->SendFile(CONFIGDIR "/zapit/services.xml");
}
//-----------------------------------------------------------------------------
// send bouquets.xml
void CControlAPI::GetBouquetsxmlCGI(CyhookHandler *hh)
{
hh->SendFile(CONFIGDIR "/zapit/bouquets.xml");
}
//-----------------------------------------------------------------------------
// send ubouquets.xml
void CControlAPI::GetUBouquetsxmlCGI(CyhookHandler *hh)
{
hh->SendFile(CONFIGDIR "/zapit/ubouquets.xml");
}
//-----------------------------------------------------------------------------
// get actual channel_id
void CControlAPI::GetChannel_IDCGI(CyhookHandler *hh)
{
CZapitClient::CCurrentServiceInfo current_pids = NeutrinoAPI->Zapit->getCurrentServiceInfo();
hh->printf("%x%04x%04x\n",current_pids.tsid, current_pids.onid, current_pids.sid);
}
// get actual channel_id
void CControlAPI::GetTPChannel_IDCGI(CyhookHandler *hh)
{
SendChannelList(hh, true);
}
//-----------------------------------------------------------------------------
void CControlAPI::MessageCGI(CyhookHandler *hh)
{
std::string message;
int event = 0;
if (!(hh->ParamList["popup"].empty()))
{
message = hh->ParamList["popup"];
event = NeutrinoMessages::EVT_POPUP;
}
else if (!(hh->ParamList["nmsg"].empty()))
{
message = hh->ParamList["nmsg"];
event = NeutrinoMessages::EVT_EXTMSG;
}
else
{
hh->SendError();
return;
}
if (!(hh->ParamList["timeout"].empty()))
{
message += "&timeout=";
message += hh->ParamList["timeout"];
}
if (event != 0)
{
//message=decodeString(message);
NeutrinoAPI->EventServer->sendEvent(event, CEventServer::INITID_HTTPD, (void *) message.c_str(), message.length() + 1);
hh->SendOk();
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::InfoCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty())
hh->Write("Neutrino HD\n");
else
{
if (hh->ParamList["1"] == "streaminfo") // print streaminfo
SendStreamInfo(hh);
else if (hh->ParamList["1"] == "version") // send version file
hh->SendFile("/.version");
else if (hh->ParamList["1"] == "httpdversion") // print httpd version typ (only ffor comptibility)
hh->Write("3");
else if (hh->ParamList["1"] == "nhttpd_version")// print nhttpd version
hh->printf("%s\n", HTTPD_VERSION);
else if (hh->ParamList["1"] == "hwinfo")// print hwinfo
HWInfoCGI(hh);
else
hh->SendError();
}
}
void CControlAPI::HWInfoCGI(CyhookHandler *hh)
{
std::string boxname = NeutrinoAPI->NeutrinoYParser->func_get_boxtype(hh, "");
std::string boxmodel = NeutrinoAPI->NeutrinoYParser->func_get_boxmodel(hh, "");
static CNetAdapter netadapter;
std::string eth_id = netadapter.getMacAddr();
std::transform(eth_id.begin(), eth_id.end(), eth_id.begin(), ::tolower);
hh->printf("%s (%s)\nMAC:%s\n", boxname.c_str(), boxmodel.c_str(), eth_id.c_str());
}
//-----------------------------------------------------------------------------
void CControlAPI::ShutdownCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty())
{
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::SHUTDOWN, CEventServer::INITID_HTTPD);
hh->SendOk();
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::RebootCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty())
{
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::REBOOT, CEventServer::INITID_HTTPD);
hh->SendOk();
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
int CControlAPI::rc_send(int ev, unsigned int code, unsigned int value)
{
struct input_event iev;
iev.type=EV_KEY;
iev.code=code;
iev.value=value;
return write(ev,&iev,sizeof(iev));
}
//-----------------------------------------------------------------------------
// The code here is based on rcsim. Thx Carjay!
void CControlAPI::RCEmCGI(CyhookHandler *hh) {
if (hh->ParamList.empty()) {
hh->SendError();
return;
}
std::string _keyname = hh->ParamList["1"];
int sendcode = -1;
for (unsigned int i = 0; sendcode == -1 && i < sizeof(keyname)
/ sizeof(key); i++) {
if (!strcmp(_keyname.c_str(), keyname[i].name))
sendcode = keyname[i].code;
}
if (sendcode == -1) {
printf("[nhttpd] Key %s not found\n", _keyname.c_str());
hh->SendError();
return;
}
#if 0
unsigned int repeat = 1;
unsigned int delay = 250;
if (!hh->ParamList["delay"].empty())
delay = atoi(hh->ParamList["delay"].c_str());
if (!hh->ParamList["duration"].empty())
repeat = atoi(hh->ParamList["duration"].c_str()) * 1000 / delay;
if (!hh->ParamList["repeat"].empty())
repeat = atoi(hh->ParamList["repeat"].c_str());
#endif
int evd = open(EVENTDEV, O_RDWR);
if (evd < 0) {
hh->SendError();
perror("opening event0 failed");
return;
}
if (rc_send(evd, sendcode, KEY_PRESSED) < 0) {
perror("writing 'KEY_PRESSED' event failed");
hh->SendError();
close(evd);
return;
}
if (rc_send(evd, sendcode, KEY_RELEASED) < 0) {
perror("writing 'KEY_RELEASED' event failed");
close(evd);
hh->SendError();
return;
}
close(evd);
hh->SendOk();
}
//-----------------------------------------------------------------------------
void CControlAPI::AspectRatioCGI(CyhookHandler *hh)
{
hh->printf("%s",(NeutrinoAPI->getVideoAspectRatioAsString()).c_str());
}
//-----------------------------------------------------------------------------
void CControlAPI::VideoFormatCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty() || hh->ParamList["1"] == "status") {
hh->printf("%s",(NeutrinoAPI->getVideoAspectRatioAsString()).c_str());
return;
}
if (NeutrinoAPI->setVideoAspectRatioAsString(hh->ParamList["1"]) != -1)
hh->SendOk();
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::VideoOutputCGI(CyhookHandler *hh)
{
// FIXME: not implemented
hh->SendOk();
}
//-----------------------------------------------------------------------------
void CControlAPI::VCROutputCGI(CyhookHandler *hh)
{
// FIXME: not implemented
hh->SendOk();
}
//-----------------------------------------------------------------------------
void CControlAPI::ScartModeCGI(CyhookHandler *hh)
{
// FIXME: not implemented
hh->SendOk();
}
//-----------------------------------------------------------------------------
void CControlAPI::AudioCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty() || hh->ParamList["1"] == "info") {
hh->printf("%s",(NeutrinoAPI->getAudioInfoAsString()).c_str());
return;
}
//TODO: more
}
//-------------------------------------------------------------------------
void CControlAPI::VolumeCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty()) {//without param: show actual volumen
unsigned int volume;
NeutrinoAPI->Zapit->getVolume(&volume, &volume);
hh->printf("%d", volume);
}
else if (hh->ParamList["1"].compare("mute") == 0)
{
char mute = 1;
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::EVT_SET_MUTE, CEventServer::INITID_HTTPD, (void *)&mute, sizeof(char));
hh->SendOk();
}
else if (hh->ParamList["1"].compare("unmute") == 0)
{
char mute = 0;
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::EVT_SET_MUTE, CEventServer::INITID_HTTPD, (void *)&mute, sizeof(char));
hh->SendOk();
}
else if (hh->ParamList["1"].compare("status") == 0) { // Mute status
(NeutrinoAPI->Zapit->getMuteStatus()) ? hh->Write("1") : hh->Write("0");
}
else if(!hh->ParamList["1"].empty()) { //set volume
char vol = atol( hh->ParamList["1"].c_str() );
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::EVT_SET_VOLUME, CEventServer::INITID_HTTPD, (void *)&vol, sizeof(char));
hh->SendOk();
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::CryptCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty() || hh->ParamList["1"] == "info") {
hh->printf("%s",(NeutrinoAPI->getCryptInfoAsString()).c_str());
return;
}
//TODO: more
}
//-----------------------------------------------------------------------------
void CControlAPI::ChannellistCGI(CyhookHandler *hh)
{
SendChannelList(hh);
}
void CControlAPI::LogolistCGI(CyhookHandler *hh)
{
hh->outStart();
std::string result = "";
bool isFirstLine = true;
bool files = false;
unsigned int s = hh->ParamList.size();
for (unsigned int i = 1; i <= s; i++)
{
files = (hh->ParamList[itoa(i)] == "files" && hh->ParamList["files"] != "false");
if (files)
break;
}
int mode = NeutrinoAPI->Zapit->getMode();
CBouquetManager::ChannelIterator cit = mode == CZapitClient::MODE_RADIO ? g_bouquetManager->radioChannelsBegin() : g_bouquetManager->tvChannelsBegin();
for (; !(cit.EndOfChannels()); cit++)
{
std::string item = "";
std::string id = "";
std::string logo = "";
std::vector<t_channel_id> v;
CZapitChannel * channel = *cit;
size_t pos = std::find(v.begin(), v.end(), channel->getChannelID()) - v.begin();
if (pos < v.size())
continue;
v.push_back(channel->getChannelID());
std::string logo_used = "";
std::string logo_real = "";
if (files)
{
char _real[PATH_MAX + 1] = {0};
if (g_PicViewer->GetLogoName(channel->getChannelID(), NeutrinoAPI->GetServiceName(channel->getChannelID()), logo_used, NULL, NULL))
{
realpath(logo_used.c_str(), _real);
logo_real = string(_real);
if (strcmp(logo_used.c_str(), logo_real.c_str()) == 0)
logo_real.clear();
}
}
if (hh->outType == plain)
{
std::string outLine = string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS";%s;" PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS"", channel->getChannelID(), channel->getName().c_str(), (channel->getChannelID() & 0xFFFFFFFFFFFFULL));
if (files)
{
if (!logo_used.empty())
outLine += string_printf(";%s", logo_used.c_str());
if (!logo_real.empty())
outLine += string_printf(";%s", logo_real.c_str());
}
item = hh->outSingle(outLine);
}
else
{
item = hh->outPair("name", hh->outValue(channel->getName()), true);
id = hh->outPair("id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel->getChannelID()), true);
id += hh->outPair("short_id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel->getChannelID() & 0xFFFFFFFFFFFFULL), false);
item += hh->outObject("id", id, files);
if (files)
{
logo = hh->outPair("used", logo_used, true);
logo += hh->outPair("real", logo_real, false);
item += hh->outObject("logo", logo);
}
}
if (isFirstLine)
isFirstLine = false;
else
result += hh->outNext();
result += hh->outArrayItem("channel", item, false);
}
result = hh->outArray("logolist", result);
hh->SendResult(result);
}
//-----------------------------------------------------------------------------
// get actual and next event data for given channel
//-----------------------------------------------------------------------------
std::string CControlAPI::_GetBouquetActualEPGItem(CyhookHandler *hh, CZapitChannel * channel) {
std::string result, firstEPG, secondEPG = "";
t_channel_id current_channel = CZapit::getInstance()->GetCurrentChannelID();
std::string timestr;
CShortEPGData epg;
CSectionsdClient::responseGetCurrentNextInfoChannelID currentNextInfo;
CChannelEvent *event;
NeutrinoAPI->Lock();
event = NeutrinoAPI->ChannelListEvents[channel->getChannelID()];
NeutrinoAPI->Unlock();
if (event) {
int percentage = 100;
if (event->duration > 0)
percentage = 100 * (time(NULL) - event->startTime) / event->duration;
CEitManager::getInstance()->getCurrentNextServiceKey(channel->getChannelID(), currentNextInfo);
timestr = timeString(event->startTime);
firstEPG += hh->outPair("eventid", string_printf("%llu", currentNextInfo.current_uniqueKey), true);
firstEPG += hh->outPair("description", hh->outValue(event->description), true);
if (CEitManager::getInstance()->getEPGidShort(currentNextInfo.current_uniqueKey, &epg))
{
firstEPG += hh->outPair("info1", hh->outValue(epg.info1), true);
firstEPG += hh->outPair("info2", hh->outValue(epg.info2), true);
}
firstEPG += hh->outPair("startTime", timestr, true);
firstEPG += hh->outPair("timeTotal", string_printf("%d", event->duration / 60), true);
firstEPG += hh->outPair("timeElapsed", string_printf("%d", (time(NULL) - event->startTime) / 60), true);
firstEPG += hh->outPair("percentage", string_printf("%d", percentage), false);
if (currentNextInfo.flags & CSectionsdClient::epgflags::has_next) {
timestr = timeString(currentNextInfo.next_zeit.startzeit);
secondEPG += hh->outPair("eventid", string_printf("%llu", currentNextInfo.next_uniqueKey), true);
secondEPG += hh->outPair("description", hh->outValue(currentNextInfo.next_name), true);
if (CEitManager::getInstance()->getEPGidShort(currentNextInfo.next_uniqueKey, &epg))
{
secondEPG += hh->outPair("info1", hh->outValue(epg.info1), true);
secondEPG += hh->outPair("info2", hh->outValue(epg.info2), true);
}
secondEPG += hh->outPair("startTime", timestr, true);
secondEPG += hh->outPair("timeTotal", string_printf("%d", currentNextInfo.next_zeit.dauer / 60), false);
}
}
result += hh->outPair("isActiveChannel", (channel->getChannelID() == current_channel) ? "true" : "false", (!firstEPG.empty()));
if(!firstEPG.empty()) {
result += hh->outObject("firstEPG", firstEPG);
}
if(!secondEPG.empty()) {
result += hh->outNext();
result += hh->outObject("secondEPG", secondEPG);
}
return result;
}
//-----------------------------------------------------------------------------
// produce data (collection) for given channel
std::string CControlAPI::_GetBouquetWriteItem(CyhookHandler *hh, CZapitChannel * channel, int bouquetNr, int nr) {
std::string result = "";
bool isEPGdetails = !(hh->ParamList["epg"].empty());
if (hh->outType == json || hh->outType == xml) {
result += hh->outPair("number", string_printf("%u", nr), true);
result += hh->outPair("id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel->getChannelID()), true);
result += hh->outPair("short_id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel->getChannelID()&0xFFFFFFFFFFFFULL), true);
result += hh->outPair("name", hh->outValue(channel->getName()), true);
result += hh->outPair("logo", hh->outValue(NeutrinoAPI->getLogoFile(hh->WebserverConfigList["Tuxbox.LogosURL"], channel->getChannelID())), true);
result += hh->outPair("bouquetnr", string_printf("%d", bouquetNr), isEPGdetails);
if(isEPGdetails)
result += _GetBouquetActualEPGItem(hh, channel);
result = hh->outArrayItem("channel", result, false);
}
else {
CChannelEvent *event;
NeutrinoAPI->Lock();
event = NeutrinoAPI->ChannelListEvents[channel->getChannelID()];
NeutrinoAPI->Unlock();
if (event && isEPGdetails) {
result += string_printf("%u "
PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS
" %s (%s)\n",
nr,
channel->getChannelID(),
channel->getName().c_str(), event->description.c_str());
} else {
result += string_printf("%u "
PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS
" %s\n",
nr,
channel->getChannelID(),
channel->getName().c_str());
}
}
return result;
}
//-------------------------------------------------------------------------
/** List all channels for given bouquet (or all) or show actual bouquet number
* @param hh CyhookHandler
*
* @par nhttpd-usage
* Get bouquet list (all) oder filtered to a given bouquet number
* Option epg=true for actual and next epg data for each channel
* @code
* /control/getbouquet?[bouquet=<bouquet number>][&mode=TV|RADIO][&epg=true]
* @endcode
* Get the actual used bouquet number
* @code
* /control/getbouquet?actual
* @endcode
*
* @par output (json)
* @code
* /control/getbouquet?bouquet=2&format=json
* @endcode
* @code
* {"success": "true", "data":{"channels": [ {"number": "1", "id": "12ea043100016e3d", "short_id": "43100016e3d", "name": "ARD-TEST-1", "logo": "", "bouquetnr": "1"},
* {"number": "2", "id": "4792041b00017034", "short_id": "41b00017034", "name": "arte", "logo": "", "bouquetnr": "1"},
* [...snip...]
* {"number": "26", "id": "11aa044d00016dcf", "short_id": "44d00016dcf", "name": "WDR Köln", "logo": "", "bouquetnr": "1"}]
* }}
* @endcode
*
* @par output (plain) output only (channel number, channel id, channel name)
* @code
* /control/getbouquet?bouquet=2
* @endcode
* @code
* 1 12ea043100016e3d ARD-TEST-1
* 2 4792041b00017034 arte
* [...snip...]
* 25 4792041b00017036 Test-R
* 26 11aa044d00016dcf WDR Köln
* @endcode
*
* @par output (xml)
* @code
* /control/getbouquet?bouquet=2&format=xml
* @endcode
* @code
* <channels>
* <channel>
* <number>1</number>
* <bouquet>1</bouquet>
* <id>12ea043100016e3d</id>
* <short_id>43100016e3d</short_id>
* <name><![CDATA[ARD-TEST-1]]></name>
* <logo><![CDATA[]]></logo>
* </channel>
* [...snip...]
* <channel>
* <number>26</number>
* <bouquet>1</bouquet>
* <id>11aa044d00016dcf</id>
* <short_id>44d00016dcf</short_id>
* <name><![CDATA[WDR Köln]]></name>
* <logo><![CDATA[]]></logo>
* </channel>
* </channels>
* @endcode
*/
//-------------------------------------------------------------------------
void CControlAPI::GetBouquetCGI(CyhookHandler *hh) {
TOutType outType = hh->outStart(true /*old mode*/);
std::string result = "";
if (!(hh->ParamList.empty())) {
int mode = NeutrinoAPI->Zapit->getMode();
if (hh->ParamList["mode"].compare("TV") == 0)
mode = CZapitClient::MODE_TV;
else if (hh->ParamList["mode"].compare("RADIO") == 0)
mode = CZapitClient::MODE_RADIO;
else if (hh->ParamList["mode"].compare("all") == 0)
mode = CZapitClient::MODE_ALL;
// Get Bouquet Number. First matching current channel
if (hh->ParamList["1"] == "actual") {
int actual = 0;
for (int i = 0; i < (int) g_bouquetManager->Bouquets.size(); i++) {
if (g_bouquetManager->existsChannelInBouquet(i, CZapit::getInstance()->GetCurrentChannelID())) {
actual = i + 1;
break;
}
}
hh->printf("%d", actual);
}
else {
int BouquetNr = -1; // -1 = all bouquets
int startBouquet = 0;
int bsize = (int) g_bouquetManager->Bouquets.size();
if (!hh->ParamList["bouquet"].empty()) {
// list for given bouquet
BouquetNr = atoi(hh->ParamList["bouquet"].c_str());
if (BouquetNr > 0)
BouquetNr--;
if((BouquetNr > 0) && (BouquetNr >= bsize))
BouquetNr = bsize-1;
startBouquet = BouquetNr;
bsize = BouquetNr+1;
}
if (!(hh->ParamList["epg"].empty()))
NeutrinoAPI->GetChannelEvents();
const char *json_delimiter = "";
if (mode == CZapitClient::MODE_RADIO || mode == CZapitClient::MODE_ALL)
for (int i = startBouquet; i < bsize; i++) {
ZapitChannelList channels = g_bouquetManager->Bouquets[i]->radioChannels;
int num = 1 + g_bouquetManager->radioChannelsBegin().getNrofFirstChannelofBouquet(i);
int size = (int) channels.size();
for (int j = 0; j < size; j++) {
CZapitChannel * channel = channels[j];
result += json_delimiter;
json_delimiter = (outType == json) ? ",\n" : "";
result += _GetBouquetWriteItem(hh, channel, i, num + j);
}
}
if (mode == CZapitClient::MODE_TV || mode == CZapitClient::MODE_ALL)
for (int i = startBouquet; i < bsize; i++) {
ZapitChannelList channels = g_bouquetManager->Bouquets[i]->tvChannels;
int num = 1 + g_bouquetManager->tvChannelsBegin().getNrofFirstChannelofBouquet(i);
int size = (int) channels.size();
for (int j = 0; j < size; j++) {
CZapitChannel * channel = channels[j];
result += json_delimiter;
json_delimiter = (outType == json) ? ",\n" : "";
result += _GetBouquetWriteItem(hh, channel, i, num + j);
}
}
result = hh->outArray("channels", result);
hh->SendResult(result);
}
}
else
hh->SendError("no parameter");
}
//-------------------------------------------------------------------------
/** Return all bouquets
* @param hh CyhookHandler
*
* @par nhttpd-usage
* @code
* /control/getbouquets?[showhidden=true|false][&encode=true|false][&format=|xml|json]
*
* @endcode
* @par
* @e showhidden = true (default) | false -> show hidden bouquets
* @n @e encode = true | false (default) use URLencode
* @n @e Result: bouquet number, bouquet name *
*
* @par output (json)
* @code
* /control/getbouquets&format=json
* @endcode
* @code
* {"success": "true", "data":{"bouquets": [{"number": "2",
* "name": "ARD"
* },
* {"number": "12",
* "name": "Digital Free"
* },
* [...snip...]
* {"number": "23",
* "name": "Other"
* }
* ]
* }}
* @endcode
*
* @par output (plain)
* @code
* /control/getbouquets
* @endcode
* @code
* 2 ARD
* 12 Digital Free
* [...snip...]
* 22 ZDFvision
* 23 Other
* @endcode
*
* @par output (xml)
* @code
* /control/getbouquets&format=xml
* @endcode
* @code
* <bouquets>
* <bouquet>
* <number>2</number>
* <name>ARD</name>
* </bouquet>
* [...snip...]
* <number>23</number>
* <name>Other</name>
* </bouquet>
* </bouquets>
* @endcode
*/
//-------------------------------------------------------------------------
void CControlAPI::GetBouquetsCGI(CyhookHandler *hh) {
bool show_hidden = true;
bool encode = false;
std::string result = "";
TOutType outType = hh->outStart();
if (hh->ParamList["showhidden"] == "false")
show_hidden = false;
if (hh->ParamList["encode"] == "true")
encode = true;
bool fav = false;
if (hh->ParamList["fav"] == "true")
fav = true;
int mode = NeutrinoAPI->Zapit->getMode();
if (hh->ParamList["mode"].compare("all") == 0)
mode = CZapitClient::MODE_ALL;
else if (hh->ParamList["mode"].compare("TV") == 0)
mode = CZapitClient::MODE_TV;
else if (hh->ParamList["mode"].compare("RADIO") == 0)
mode = CZapitClient::MODE_RADIO;
std::string bouquet;
for (int i = 0, size = (int) g_bouquetManager->Bouquets.size(); i < size; i++) {
std::string item = "";
unsigned int channel_count = 0;
switch (mode) {
case CZapitClient::MODE_RADIO:
channel_count = g_bouquetManager->Bouquets[i]->radioChannels.size();
break;
case CZapitClient::MODE_TV:
channel_count = g_bouquetManager->Bouquets[i]->tvChannels.size();
break;
case CZapitClient::MODE_ALL:
channel_count = g_bouquetManager->Bouquets[i]->radioChannels.size() + g_bouquetManager->Bouquets[i]->tvChannels.size();
}
if (channel_count && (!g_bouquetManager->Bouquets[i]->bHidden || show_hidden) && (!fav || g_bouquetManager->Bouquets[i]->bUser)) {
bouquet = std::string(g_bouquetManager->Bouquets[i]->bFav ? g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME) : g_bouquetManager->Bouquets[i]->Name.c_str());
if (encode)
bouquet = encodeString(bouquet); // encode (URLencode) the bouquetname
if (outType == plain)
item = string_printf("%u", i + 1) + " " + bouquet + "\n";
else
{
item = hh->outPair("number", string_printf("%u", i + 1), true);
item += hh->outPair("name", bouquet, false);
}
result += hh->outArrayItem("bouquet", item, (i < size-1));
}
}
result = hh->outArray("bouquets", result);
hh->SendResult(result);
}
//-----------------------------------------------------------------------------
// details EPG Information for channelid
//-----------------------------------------------------------------------------
std::string CControlAPI::channelEPGformated(CyhookHandler *hh, int bouquetnr, t_channel_id channel_id, int max, long stoptime) {
std::string result = "";
std::string channelData = "";
CEitManager::getInstance()->getEventsServiceKey(channel_id, NeutrinoAPI->eList);
channelData += hh->outPair("channel_id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel_id), true);
channelData += hh->outPair("channel_short_id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel_id & 0xFFFFFFFFFFFFULL), true);
channelData += hh->outPair("channel_name", hh->outValue(NeutrinoAPI->GetServiceName(channel_id)), false);
if(hh->outType == json)
channelData = hh->outObject("channelData", channelData);
int i = 0;
CChannelEventList::iterator eventIterator;
bool isFirstLine = true;
for (eventIterator = NeutrinoAPI->eList.begin(); eventIterator != NeutrinoAPI->eList.end(); ++eventIterator, i++) {
if ((max != -1 && i >= max) || (stoptime != -1 && eventIterator->startTime >= stoptime))
break;
std::string prog = "";
prog += hh->outPair("bouquetnr", string_printf("%d", bouquetnr), true);
prog += hh->outPair("channel_id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel_id), true);
prog += hh->outPair("eventid", string_printf("%llu", eventIterator->eventID), true);
prog += hh->outPair("eventid_hex", string_printf("%llx", eventIterator->eventID), true);
prog += hh->outPair("start_sec", string_printf("%ld", eventIterator->startTime), true);
char zbuffer[25] = { 0 };
struct tm *mtime = localtime(&eventIterator->startTime);
strftime(zbuffer, 20, "%H:%M", mtime);
prog += hh->outPair("start_t", std::string(zbuffer), true);
memset(zbuffer, 0, sizeof(zbuffer));
strftime(zbuffer, 20, "%d.%m.%Y", mtime);
prog += hh->outPair("date", std::string(zbuffer), true);
prog += hh->outPair("stop_sec", string_printf("%ld", eventIterator->startTime + eventIterator->duration), true);
long _stoptime = eventIterator->startTime + eventIterator->duration;
mtime = localtime(&_stoptime);
strftime(zbuffer, 20, "%H:%M", mtime);
prog += hh->outPair("stop_t", std::string(zbuffer), true);
prog += hh->outPair("duration_min", string_printf("%d", (int) (eventIterator->duration / 60)), true);
if (!(hh->ParamList["details"].empty())) {
CShortEPGData epg;
if (CEitManager::getInstance()->getEPGidShort(eventIterator->eventID, &epg)) {
prog += hh->outPair("info1", hh->outValue(epg.info1), true);
prog += hh->outPair("info2", hh->outValue(epg.info2), true);
}
}
prog += hh->outPair("description", hh->outValue(eventIterator->description), false);
if(isFirstLine)
isFirstLine = false;
else
result += hh->outNext();
result += hh->outArrayItem("prog", prog, false);
}
if(hh->outType == json)
result = hh->outArray("progData", result);
result = channelData + hh->outNext() + result;
return result;
}
//-----------------------------------------------------------------------------
// Detailed EPG list in XML or JSON
//-----------------------------------------------------------------------------
void CControlAPI::epgDetailList(CyhookHandler *hh) {
// ------ get parameters -------
// max = maximal output items
int max = -1;
if (!(hh->ParamList["max"].empty()))
max = atoi(hh->ParamList["max"].c_str());
// stoptime = maximal output items until starttime >= stoptime
long stoptime = -1;
if (!(hh->ParamList["stoptime"].empty()))
stoptime = atol(hh->ParamList["stoptime"].c_str());
// determine channelid
t_channel_id channel_id = (t_channel_id) -1;
if (!(hh->ParamList["channelid"].empty())) {
sscanf(hh->ParamList["channelid"].c_str(), SCANF_CHANNEL_ID_TYPE, &channel_id);
}
else if (!(hh->ParamList["channelname"].empty())) {
channel_id = NeutrinoAPI->ChannelNameToChannelId(hh->ParamList["channelname"].c_str());
}
// or determine bouquetnr -> iterate the bouquet
int bouquetnr = -1;
bool all_bouquets = false;
if (hh->ParamList["bouquetnr"] == "all")
all_bouquets = true;
else if (!(hh->ParamList["bouquetnr"].empty())) {
bouquetnr = atoi(hh->ParamList["bouquetnr"].c_str());
bouquetnr--;
}
// ------ generate output ------
hh->outStart(true /*old mode*/);
std::string result = "";
NeutrinoAPI->eList.clear();
if (bouquetnr >= 0 || all_bouquets) {
int bouquet_size = (int) g_bouquetManager->Bouquets.size();
int start_bouquet = 0;
if(bouquetnr >= 0 && !all_bouquets) {
start_bouquet = bouquetnr;
bouquet_size = bouquetnr+1;
}
// list all bouquets if(encode)
ZapitChannelList channels;
int mode = NeutrinoAPI->Zapit->getMode();
for (int i = start_bouquet; i < bouquet_size; i++) {
channels = mode == CZapitClient::MODE_RADIO ? g_bouquetManager->Bouquets[i]->radioChannels : g_bouquetManager->Bouquets[i]->tvChannels;
std::string bouquet = std::string(g_bouquetManager->Bouquets[i]->bFav ? g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME) : g_bouquetManager->Bouquets[i]->Name.c_str());
bouquet = encodeString(bouquet); // encode (URLencode) the bouquetname
std::string res_channels = "";
for (int j = 0, csize = (int) channels.size(); j < csize; j++) {
CZapitChannel * channel = channels[j];
res_channels += hh->outArrayItem("channel", channelEPGformated(hh, j + 1, channel->getChannelID(), max, stoptime), j<csize-1);
}
if(all_bouquets) {
res_channels = hh->outPair("number", string_printf("%d", i + 1), true) +
hh->outPair("name", hh->outValue(bouquet), true) +
res_channels;
result += hh->outArrayItem("bouquet", res_channels, i < bouquet_size-1);
}
else
result += res_channels;
}
}
else
// list one channel, no bouquetnr given
result = channelEPGformated(hh, 0, channel_id, max, stoptime);
result = hh->outObject("epglist", result);
hh->SendResult(result);
}
//-------------------------------------------------------------------------------------------------
inline static bool sortByDateTime (const CChannelEvent& a, const CChannelEvent& b)
{
return a.startTime < b.startTime;
}
extern const char * GetGenre(const unsigned char contentClassification); // UTF-8
void CControlAPI::EpgSearchXMLCGI(CyhookHandler *hh)
{
SendFoundEvents(hh, true);
}
//-------------------------------------------------------------------------
/** Return EPG search data
* @param hh CyhookHandler
*
* @par nhttpd-usage
* @code
* /control/epgsearch?<keywords>
* or
* /control/epgsearch?search=<keywords>[&epginfo=true|false|search][&format=plain|xml|json]
* @endcode
*/
//-------------------------------------------------------------------------
void CControlAPI::EpgSearchCGI(CyhookHandler *hh)
{
SendFoundEvents(hh);
}
void CControlAPI::SendFoundEvents(CyhookHandler *hh, bool xml_format)
{
if (hh->ParamList.empty())
{
hh->SendError();
return;
}
std::string result ="";
std::string item = "";
t_channel_id channel_id;
CChannelEventList evtlist;
bool search_epginfo = (hh->ParamList["epginfo"] != "false");
bool return_epginfo = (hh->ParamList["epginfo"] == "true" || hh->ParamList["epginfo"].empty());
std::string search_keyword = (hh->ParamList["search"].empty()) ? hh->ParamList["1"] : hh->ParamList["search"];
const int search_epg_item = search_epginfo ? 5 /*SEARCH_EPG_ALL*/ : 1 /*SEARCH_EPG_TITLE*/;
if (xml_format) // to stay backward compatible :/
hh->ParamList["format"] = "xml";
hh->outStart(true /*old mode*/);
/* TODO: maybe add following options as in tuxbox neutrino
hh->ParamList["epgitem"]
hh->ParamList["mode"]
hh->ParamList["channelid"]
hh->ParamList["channelname"]
hh->ParamList["bouquet"]
*/
std::vector<t_channel_id> v;
int channel_nr = CNeutrinoApp::getInstance()->channelList->getSize(); //unique channelList TV or Radio
for (int channel = 0; channel < channel_nr; channel++)
{
channel_id = CNeutrinoApp::getInstance()->channelList->getChannelFromIndex(channel)->getChannelID();
v.push_back(channel_id);
}
std::map<t_channel_id, t_channel_id> ch_id_map;
std::vector<t_channel_id>::iterator it;
for (it = v.begin(); it != v.end(); ++it)
{
ch_id_map[*it & 0xFFFFFFFFFFFFULL] = *it;
}
CEitManager::getInstance()->getEventsServiceKey(0, evtlist, search_epg_item, search_keyword, true);
if (!evtlist.empty())
{
std::map<t_channel_id, t_channel_id>::iterator map_it;
CChannelEventList::iterator e;
for (e = evtlist.begin(); e != evtlist.end(); ++e)
{
map_it = ch_id_map.find(e->channelID);
if (map_it != ch_id_map.end())
{
e->channelID = map_it->second;//map channelID48 to channelID
}
else
{
evtlist.erase(e--);// remove event for not found channels in channelList
}
}
}
if (!evtlist.empty())
{
sort(evtlist.begin(), evtlist.end(), sortByDateTime);
}
time_t azeit=time(NULL);
CShortEPGData epg;
CEPGData longepg;
char tmpstr[256] ={0};
std::string genre;
CChannelEventList::iterator eventIterator;
unsigned int u_azeit = ( azeit > -1)? azeit:0;
for (eventIterator = evtlist.begin(); eventIterator != evtlist.end(); ++eventIterator)
{
bool got_next = (eventIterator != (evtlist.end() - 1));
if (CEitManager::getInstance()->getEPGidShort(eventIterator->eventID, &epg))
{
if( (eventIterator->startTime+eventIterator->duration) < u_azeit)
continue;
struct tm *tmStartZeit = localtime(&eventIterator->startTime);
item.clear();
if (hh->outType == json || hh->outType == xml)
{
item += hh->outPair("channelname", NeutrinoAPI->GetServiceName(eventIterator->channelID), true);
item += hh->outPair("epgtitle", hh->outValue(epg.title), true);
if (return_epginfo) {
item += hh->outPair("info1", hh->outValue(epg.info1), true);
item += hh->outPair("info2", hh->outValue(epg.info2), true);
}
if (CEitManager::getInstance()->getEPGid(eventIterator->eventID, eventIterator->startTime, &longepg))
{
item += hh->outPair("fsk", string_printf("%u", longepg.fsk), true);
genre = "";
#ifdef FULL_CONTENT_CLASSIFICATION
if (!longepg.contentClassification.empty())
genre = GetGenre(longepg.contentClassification[0]);
#else
if (longepg.contentClassification)
genre = GetGenre(longepg.contentClassification);
#endif
item += hh->outPair("genre", ZapitTools::UTF8_to_UTF8XML(genre.c_str()), true);
}
strftime(tmpstr, sizeof(tmpstr), "%Y-%m-%d", tmStartZeit );
item += hh->outPair("date", tmpstr, true);
strftime(tmpstr, sizeof(tmpstr), "%H:%M", tmStartZeit );
item += hh->outPair("time", tmpstr, true);
item += hh->outPair("duration", string_printf("%d", eventIterator->duration / 60), true);
item += hh->outPair("channel_id", string_printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, eventIterator->channelID), true);
item += hh->outPair("eventid", string_printf("%ld", eventIterator->eventID), false);
result += hh->outArrayItem("item", item, got_next);
}
else // outType == plain
{
std::string datetimer_str ;
strftime(tmpstr, sizeof(tmpstr), "%Y-%m-%d %H:%M", tmStartZeit );
datetimer_str = tmpstr;
datetimer_str += " ";
datetimer_str += g_Locale->getText(CLocaleManager::getMonth(tmStartZeit));
datetimer_str += " ";
datetimer_str += g_Locale->getText(CLocaleManager::getWeekday(tmStartZeit));
snprintf(tmpstr, sizeof(tmpstr)," [%d min]",eventIterator->duration / 60);
datetimer_str += tmpstr;
result += hh->outSingle(datetimer_str);
result += hh->outSingle(NeutrinoAPI->GetServiceName(eventIterator->channelID));
result += hh->outSingle(epg.title);
if (return_epginfo) {
if(!epg.info1.empty())
result += hh->outSingle(epg.info1);
if(!epg.info2.empty())
result += hh->outSingle(epg.info2);
}
if (CEitManager::getInstance()->getEPGid(eventIterator->eventID, eventIterator->startTime, &longepg)) {
result += hh->outSingle(string_printf("fsk:%u", longepg.fsk));
genre = "";
#ifdef FULL_CONTENT_CLASSIFICATION
if (!longepg.contentClassification.empty())
genre = GetGenre(longepg.contentClassification[0]);
#else
if (longepg.contentClassification)
genre = GetGenre(longepg.contentClassification);
#endif
if(!genre.empty())
result += hh->outSingle(ZapitTools::UTF8_to_UTF8XML(genre.c_str()));
}
result += hh->outSingle("----------------------------------------------------------");
}
}
}
result = hh->outArray("epgsearch", result);
hh->SendResult(result);
}
//-------------------------------------------------------------------------
/** Return EPG data
* @param hh CyhookHandler
*
* @par nhttpd-usage
* @code
* /control/epg
* /control/epg?<channelid64> 64Bit, hex
* /control/epg?id=<channelid>
* /control/epg?search=<keywords>
* /control/epg?eventid=<eventid>
* /control/epg?ext
* /control/epg?xml=true&channelid=<channelid>|channelname=<channel name>[&details=true][&max=<max items>][&stoptime=<long:stop time>]
* details=true : Show EPG Info1 and info2
* stoptime : show only items until stoptime reached
* @endcode
*/
//-------------------------------------------------------------------------
void CControlAPI::EpgCGI(CyhookHandler *hh) {
NeutrinoAPI->eList.clear();
bool param_empty = hh->ParamList.empty();
hh->SetHeader(HTTP_OK, "text/plain; charset=UTF-8"); // default
// Detailed EPG list in XML or JSON
if (hh->getOutType() == xml || hh->getOutType() == json || !hh->ParamList["detaillist"].empty()) {
epgDetailList(hh);
}
// Standard list normal or extended
else if (param_empty || hh->ParamList["1"] == "ext") {
hh->SetHeader(HTTP_OK, "text/plain; charset=UTF-8");
bool isExt = (hh->ParamList["1"] == "ext");
CChannelEvent *event = NULL;
NeutrinoAPI->GetChannelEvents();
int mode = NeutrinoAPI->Zapit->getMode();
CBouquetManager::ChannelIterator cit = mode == CZapitClient::MODE_RADIO ? g_bouquetManager->radioChannelsBegin() : g_bouquetManager->tvChannelsBegin();
for (; !(cit.EndOfChannels()); cit++) {
CZapitChannel * channel = *cit;
NeutrinoAPI->Lock();
event = NeutrinoAPI->ChannelListEvents[channel->getChannelID()];
NeutrinoAPI->Unlock();
if (event) {
if (!isExt) {
hh->printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS
" %llu %s\n", channel->getChannelID(), event->eventID, event->description.c_str());
}
else { // ext output
hh->printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS
" %ld %u %llu %s\n", channel->getChannelID(), event->startTime, event->duration, event->eventID, event->description.c_str());
}
}
}
}
else if (!hh->ParamList["search"].empty())
{
SendFoundEvents(hh, (hh->getOutType() == xml));
}
// query details for given eventid
else if (!hh->ParamList["eventid"].empty()) {
//special epg query
uint64_t epgid = 0;
sscanf(hh->ParamList["eventid"].c_str(), "%llu", &epgid);
CShortEPGData epg;
if (CEitManager::getInstance()->getEPGidShort(epgid, &epg)) {
hh->WriteLn(epg.title);
hh->WriteLn(epg.info1);
hh->WriteLn(epg.info2);
}
}
else if (!hh->ParamList["eventid2fsk"].empty()) {
if (!hh->ParamList["starttime"].empty()) {
uint64_t epgid = 0;
time_t starttime = 0;
sscanf(hh->ParamList["fskid"].c_str(), "%llu", &epgid);
sscanf(hh->ParamList["starttime"].c_str(), "%lu", &starttime);
CEPGData longepg;
if (CEitManager::getInstance()->getEPGid(epgid, starttime, &longepg)) {
hh->printf("%u\n", longepg.fsk);
return;
}
}
hh->SendError();
}
// list EPG for channel id
else if (!(hh->ParamList["id"].empty())) {
t_channel_id channel_id = 0;
sscanf(hh->ParamList["id"].c_str(), SCANF_CHANNEL_ID_TYPE, &channel_id);
CEitManager::getInstance()->getEventsServiceKey(channel_id, NeutrinoAPI->eList);
CChannelEventList::iterator eventIterator;
for (eventIterator = NeutrinoAPI->eList.begin(); eventIterator != NeutrinoAPI->eList.end(); ++eventIterator) {
CShortEPGData epg;
if (CEitManager::getInstance()->getEPGidShort(eventIterator->eventID, &epg)) {
hh->printf("%llu %ld %d\n", eventIterator->eventID, eventIterator->startTime, eventIterator->duration);
hh->printf("%s\n", epg.title.c_str());
hh->printf("%s\n", epg.info1.c_str());
hh->printf("%s\n\n", epg.info2.c_str());
}
}
}
// list EPG for channelID 64Bit
else {
//eventlist for a chan
t_channel_id channel_id = 0;
sscanf(hh->ParamList["1"].c_str(), SCANF_CHANNEL_ID_TYPE, &channel_id);
SendEventList(hh, channel_id);
}
}
//-----------------------------------------------------------------------------
void CControlAPI::VersionCGI(CyhookHandler *hh)
{
hh->SendFile("/.version");
}
//-----------------------------------------------------------------------------
void CControlAPI::ReloadNeutrinoSetupCGI(CyhookHandler *hh)
{
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::RELOAD_SETUP, CEventServer::INITID_HTTPD);
hh->SendOk();
}
void CControlAPI::ReloadPluginsCGI(CyhookHandler *hh)
{
g_PluginList->loadPlugins();
hh->SendOk();
}
void CControlAPI::ReloadChannelsCGI(CyhookHandler *hh)
{
CServiceManager::getInstance()->SaveServices(true, true);
NeutrinoAPI->Zapit->reinitChannels();
CNeutrinoApp::getInstance()->SDTreloadChannels = false;
hh->SendOk();
}
void CControlAPI::ScreenshotCGI(CyhookHandler *hh)
{
bool enableOSD = true;
bool enableVideo = true;
std::string filename = "screenshot";
if(hh->ParamList["osd"] == "0")
enableOSD = false;
if(hh->ParamList["video"] == "0")
enableVideo = false;
if(!hh->ParamList["name"].empty())
filename = hh->ParamList["name"];
CScreenShot * sc = new CScreenShot("/tmp/" + filename + ".png", (CScreenShot::screenshot_format_t)0 /*PNG*/);
sc->EnableOSD(enableOSD);
sc->EnableVideo(enableVideo);
#if 0
sc->Start();
hh->SendOk(); // FIXME what if sc->Start() failed?
#else
if (sc->StartSync())
hh->SendOk();
else
hh->SendError();
#endif
}
//-----------------------------------------------------------------------------
void CControlAPI::ZaptoCGI(CyhookHandler *hh)
{
if (hh->ParamList.empty())
{
hh->printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS
"\n",
NeutrinoAPI->Zapit->getCurrentServiceID());
return;
}
else
{
if (hh->ParamList["1"] == "getpids") // getpids !
SendcurrentVAPid(hh);
else if (hh->ParamList["1"] == "getallpids") // getpids !
SendAllCurrentVAPid(hh);
else if (hh->ParamList["1"] == "stopplayback")
{
if(NeutrinoAPI->Zapit->isPlayBackActive()){
NeutrinoAPI->Zapit->stopPlayBack();
NeutrinoAPI->Sectionsd->setPauseScanning(true);
}
hh->SendOk();
}
else if (hh->ParamList["1"] == "startplayback")
{
if(!NeutrinoAPI->Zapit->isPlayBackActive()){
NeutrinoAPI->Zapit->startPlayBack();
NeutrinoAPI->Sectionsd->setPauseScanning(false);
dprintf("start playback requested..\n");
}
hh->SendOk();
}
else if (hh->ParamList["1"] == "statusplayback")
hh->Write((char *) (NeutrinoAPI->Zapit->isPlayBackActive() ? "1" : "0"));
else if (hh->ParamList["1"] == "stopsectionsd")
{
NeutrinoAPI->Sectionsd->setPauseScanning(true);
hh->SendOk();
}
else if (hh->ParamList["1"] == "startsectionsd")
{
NeutrinoAPI->Sectionsd->setPauseScanning(false);
hh->SendOk();
}
else if (hh->ParamList["1"] == "statussectionsd")
hh->Write((char *) (NeutrinoAPI->Sectionsd->getIsScanningActive() ? "1" : "0"));
else if (hh->ParamList["1"] == "getallsubchannels")
{
t_channel_id current_channel = NeutrinoAPI->Zapit->getCurrentServiceID();
CSectionsdClient::LinkageDescriptorList desc;
CSectionsdClient::responseGetCurrentNextInfoChannelID currentNextInfo;
CEitManager::getInstance()->getCurrentNextServiceKey(current_channel, currentNextInfo);
if (currentNextInfo.flags & CSectionsdClient::epgflags::current_has_linkagedescriptors &&
CEitManager::getInstance()->getLinkageDescriptorsUniqueKey(currentNextInfo.current_uniqueKey, desc))
{
CZapitChannel * channel = CServiceManager::getInstance()->FindChannel(current_channel);
t_satellite_position satellitePosition = channel->getSatellitePosition();
for(unsigned int i=0; i< desc.size(); i++)
{
t_channel_id sub_channel_id =
((uint64_t) ( satellitePosition >= 0 ? satellitePosition : (uint64_t)(0xF000+ abs(satellitePosition))) << 48) |
(uint64_t) CREATE_CHANNEL_ID(desc[i].serviceId, desc[i].originalNetworkId, desc[i].transportStreamId);
hh->printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS
" %s\n",
sub_channel_id,
(desc[i].name).c_str());
}
}
}
else if (!hh->ParamList["subchannel"].empty())
{
extern CRemoteControl * g_RemoteControl;
if (!g_RemoteControl->subChannels.empty())
{
NeutrinoAPI->ZapToSubService(hh->ParamList["subchannel"].c_str());
hh->SendOk();
}
else
hh->SendError();
}
else if (!hh->ParamList["name"].empty())
{
t_channel_id channel_id;
channel_id = NeutrinoAPI->ChannelNameToChannelId(hh->ParamList["name"]);
if(channel_id != (t_channel_id)-1)
{
NeutrinoAPI->ZapToChannelId(channel_id);
hh->SendOk();
}
else
hh->SendError();
}
else
{
NeutrinoAPI->ZapTo(hh->ParamList["1"].c_str());
hh->SendOk();
}
return;
}
hh->SendError();
return;
}
//-----------------------------------------------------------------------------
void CControlAPI::StartPluginCGI(CyhookHandler *hh)
{
std::string pluginname;
if (!(hh->ParamList.empty()))
{
if (!hh->ParamList["name"].empty())
{
pluginname = hh->ParamList["name"];
//pluginname=decodeString(pluginname);
NeutrinoAPI->EventServer->sendEvent(NeutrinoMessages::EVT_START_PLUGIN,
CEventServer::INITID_HTTPD,
(void *) pluginname.c_str(),
pluginname.length() + 1);
hh->SendOk();
}
else
hh->SendError();
}
else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::LCDAction(CyhookHandler *hh)
{
hh->SendOk();
}
//-------------------------------------------------------------------------
// Send functions (for ExecuteCGI)
//-------------------------------------------------------------------------
void CControlAPI::SendEventList(CyhookHandler *hh, t_channel_id channel_id)
{
int pos = 0;
CEitManager::getInstance()->getEventsServiceKey(channel_id, NeutrinoAPI->eList);
CChannelEventList::iterator eventIterator;
for (eventIterator = NeutrinoAPI->eList.begin(); eventIterator != NeutrinoAPI->eList.end(); ++eventIterator, pos++)
hh->printf("%llu %ld %d %s\n", eventIterator->eventID, eventIterator->startTime, eventIterator->duration, eventIterator->description.c_str());
}
//-----------------------------------------------------------------------------
void CControlAPI::SendChannelList(CyhookHandler *hh, bool currentTP)
{
t_channel_id current_channel = 0;
std::vector<t_channel_id> v;
if(currentTP){
current_channel = CZapit::getInstance()->GetCurrentChannelID();
current_channel=(current_channel>>16);
}
int mode = NeutrinoAPI->Zapit->getMode();
hh->SetHeader(HTTP_OK, "text/plain; charset=UTF-8");
CBouquetManager::ChannelIterator cit = mode == CZapitClient::MODE_RADIO ? g_bouquetManager->radioChannelsBegin() : g_bouquetManager->tvChannelsBegin();
for (; !(cit.EndOfChannels()); cit++) {
CZapitChannel * channel = *cit;
if(!currentTP || (channel->getChannelID() >>16) == current_channel){
size_t pos = std::find(v.begin(), v.end(), channel->getChannelID()) - v.begin();
if( pos < v.size() )
continue;
v.push_back(channel->getChannelID());
hh->printf(PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS " %s\n", channel->getChannelID(), channel->getName().c_str());
}
}
}
//-----------------------------------------------------------------------------
void CControlAPI::SignalInfoCGI(CyhookHandler *hh)
{
CFrontend *frontend = CFEManager::getInstance()->getLiveFE();
if(frontend){
bool parame_empty = false;
if (hh->ParamList["1"].empty())
parame_empty = true;
if ( parame_empty || (hh->ParamList["1"] == "sig") ){
unsigned int sig = frontend->getSignalStrength() & 0xFFFF;
sig = (sig & 0xFFFF) * 100 / 65535;
if (parame_empty)
hh->printf("SIG: ");
hh->printf("%3u\n", sig);
}
if ( parame_empty || (hh->ParamList["1"] == "snr") ){
unsigned int snr = frontend->getSignalNoiseRatio() & 0xFFFF;
snr = (snr & 0xFFFF) * 100 / 65535;
if (parame_empty)
hh->printf("SNR: ");
hh->printf("%3u\n", snr);
}
if ( parame_empty || (hh->ParamList["1"] == "ber") ){
unsigned int ber = frontend->getBitErrorRate();
if (parame_empty)
hh->printf("BER: ");
hh->printf("%3u\n", ber);
}
}else
hh->SendError();
}
//-----------------------------------------------------------------------------
void CControlAPI::SendStreamInfo(CyhookHandler *hh)
{
hh->WriteLn(NeutrinoAPI->getVideoResolutionAsString());
hh->WriteLn(NeutrinoAPI->getVideoAspectRatioAsString());
hh->WriteLn(NeutrinoAPI->getVideoFramerateAsString());
hh->WriteLn(NeutrinoAPI->getAudioInfoAsString());
}
//-----------------------------------------------------------------------------
void CControlAPI::SendcurrentVAPid(CyhookHandler *hh)
{
CZapitClient::responseGetPIDs pids;
pids.PIDs.vpid=0;
NeutrinoAPI->Zapit->getPIDS(pids);
hh->printf("%u\n", pids.PIDs.vpid);
if(!pids.APIDs.empty())
hh->printf("%u\n", pids.APIDs[0].pid);
else
hh->printf("0\n");
}
//-----------------------------------------------------------------------------
void CControlAPI::SendAllCurrentVAPid(CyhookHandler *hh)
{
static bool init_iso=true;
if(init_iso)
{
if(_initialize_iso639_map())
init_iso=false;
}
bool eit_not_ok=true;
CZapitClient::responseGetPIDs pids;
CSectionsdClient::ComponentTagList tags;
pids.PIDs.vpid=0;
NeutrinoAPI->Zapit->getPIDS(pids);
hh->printf("%05u\n", pids.PIDs.vpid);
t_channel_id current_channel = NeutrinoAPI->Zapit->getCurrentServiceID();
CSectionsdClient::responseGetCurrentNextInfoChannelID currentNextInfo;
CEitManager::getInstance()->getCurrentNextServiceKey(current_channel, currentNextInfo);
if (CEitManager::getInstance()->getComponentTagsUniqueKey(currentNextInfo.current_uniqueKey,tags))
{
for (unsigned int i=0; i< tags.size(); i++)
{
for (unsigned short j=0; j< pids.APIDs.size(); j++)
{
if ( pids.APIDs[j].component_tag == tags[i].componentTag )
{
if(!tags[i].component.empty())
{
if(!(isalnum(tags[i].component[0])))
tags[i].component=tags[i].component.substr(1,tags[i].component.length()-1);
hh->printf("%05u %s\n",pids.APIDs[j].pid,tags[i].component.c_str());
}
else
{
if(!(init_iso))
{
strncpy( pids.APIDs[j].desc, _getISO639Description( pids.APIDs[j].desc ),DESC_MAX_LEN );
}
hh->printf("%05u %s %s\n",pids.APIDs[j].pid,pids.APIDs[j].desc,pids.APIDs[j].is_ac3 ? " (AC3)": pids.APIDs[j].desc,pids.APIDs[j].is_aac ? "(AAC)" : pids.APIDs[j].desc,pids.APIDs[j].is_eac3 ? "(EAC3)" : " ");
}
eit_not_ok=false;
break;
}
}
}
}
if(eit_not_ok)
{
unsigned short i = 0;
for (CZapitClient::APIDList::iterator it = pids.APIDs.begin(); it!=pids.APIDs.end(); ++it)
{
if(!(init_iso))
{
strncpy( pids.APIDs[i].desc, _getISO639Description( pids.APIDs[i].desc ),DESC_MAX_LEN );
}
hh->printf("%05u %s %s\n",it->pid,pids.APIDs[i].desc,pids.APIDs[i].is_ac3 ? " (AC3)": pids.APIDs[i].desc,pids.APIDs[i].is_aac ? "(AAC)" : pids.APIDs[i].desc,pids.APIDs[i].is_eac3 ? "(EAC3)" : " ");
i++;
}
}
if(pids.APIDs.empty())
hh->printf("0\n"); // shouldnt happen, but print at least one apid
if(pids.PIDs.vtxtpid)
hh->printf("%05u vtxt\n",pids.PIDs.vtxtpid);
if (pids.PIDs.pmtpid)
hh->printf("%05u pmt\n",pids.PIDs.pmtpid);
if (pids.PIDs.pcrpid)
hh->printf("%05u pcr\n",pids.PIDs.pcrpid);
}
//-----------------------------------------------------------------------------
void CControlAPI::SendTimers(CyhookHandler *hh)
{
CTimerd::TimerList timerlist; // List of bouquets
bool send_id = false;
if (hh->ParamList["format"] == "id")
send_id = true;
timerlist.clear();
NeutrinoAPI->Timerd->getTimerList(timerlist);
CTimerd::TimerList::iterator timer = timerlist.begin();
for(; timer != timerlist.end(); ++timer)
{
// Add Data
char zAddData[22+1] = { 0 };
if (send_id)
{
zAddData[0] = '0';
zAddData[1] = 0;
}
switch(timer->eventType) {
//case CTimerd::TIMER_NEXTPROGRAM:
case CTimerd::TIMER_ZAPTO:
case CTimerd::TIMER_RECORD:
if (!send_id)
{
strncpy(zAddData, NeutrinoAPI->GetServiceName(timer->channel_id).c_str(), 22);
if (zAddData[0] == 0)
strcpy(zAddData, CServiceManager::getInstance()->IsChannelTVChannel(timer->channel_id) ?
"Unknown TV-Channel" : "Unknown Radio-Channel");
}
else
snprintf(zAddData,sizeof(zAddData), PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, timer->channel_id);
zAddData[22]=0;
break;
case CTimerd::TIMER_STANDBY:
if (!send_id)
snprintf(zAddData,sizeof(zAddData),"Standby: %s",(timer->standby_on ? "ON" : "OFF"));
break;
case CTimerd::TIMER_REMIND :
if (!send_id)
strncpy(zAddData, timer->message, 22);
zAddData[22]=0;
break;
default:
break;
}
hh->printf("%d %d %d %d %d %d %d %s\n",
timer->eventID,
(int)timer->eventType,
(int)timer->eventRepeat,
(int)timer->repeatCount,
(int)timer->announceTime,
(int)timer->alarmTime,
(int)timer->stopTime,
zAddData);
}
}
//-----------------------------------------------------------------------------
void CControlAPI::_SendTime(CyhookHandler *hh, struct tm *Time, int digits) {
char zTime[25] = {0};
char zDate[25] = {0};
strftime(zTime,20,"%H:%M",Time);
strftime(zDate,20,"%d.%m.%Y",Time);
hh->printf("\t\t\t\t\t<text>%s %s</text>\n",zDate,zTime);
hh->printf("\t\t\t\t\t<date>%s</date>\n",zDate);
hh->printf("\t\t\t\t\t<time>%s</time>\n",zTime);
hh->printf("\t\t\t\t\t<digits>%d</digits>\n",digits);
hh->printf("\t\t\t\t\t<day>%d</day>\n",Time->tm_mday);
hh->printf("\t\t\t\t\t<month>%d</month>\n",Time->tm_mon+1);
hh->printf("\t\t\t\t\t<year>%d</year>\n",Time->tm_year+1900);
hh->printf("\t\t\t\t\t<hour>%d</hour>\n",Time->tm_hour);
hh->printf("\t\t\t\t\t<min>%d</min>\n",Time->tm_min);
}
//-----------------------------------------------------------------------------
// build xml for all timer data (needed for yWeb 3)
//-----------------------------------------------------------------------------
void CControlAPI::SendTimersXML(CyhookHandler *hh)
{
// Init local timer iterator
CTimerd::TimerList timerlist; // List of timers
timerlist.clear();
NeutrinoAPI->Timerd->getTimerList(timerlist);
sort(timerlist.begin(), timerlist.end()); // sort timer
CTimerd::TimerList::iterator timer = timerlist.begin();
// std::string xml_response = "";
hh->SetHeader(HTTP_OK, "text/xml; charset=UTF-8");
hh->WriteLn("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
hh->WriteLn("<timer>\n");
// general timer configuration
hh->WriteLn("\t<config>\n");
// Look for Recording Safety Timers too
int pre=0, post=0;
NeutrinoAPI->Timerd->getRecordingSafety(pre,post);
// hh->printf("\t\t\t<recording_safety>%d</recording_safety>\n",(int)timer->recordingSafety);
hh->printf("\t\t\t<pre_delay>%d</pre_delay>\n",pre);
hh->printf("\t\t\t<post_delay>%d</post_delay>\n",post);
hh->WriteLn("\t</config>\n");
// start timer list
hh->WriteLn("\t<timer_list>\n");
for(; timer != timerlist.end(); ++timer)
{
hh->WriteLn("\t\t<timer>\n");
hh->printf("\t\t\t<type>%s</type>\n",(NeutrinoAPI->timerEventType2Str(timer->eventType)).c_str());
hh->printf("\t\t\t<id>%d</id>\n",timer->eventID);
hh->printf("\t\t\t<state>%d</state>\n",(int)timer->eventState);
hh->printf("\t\t\t<type_number>%d</type_number>\n",(int)timer->eventType);
// alarmtime
hh->WriteLn("\t\t\t<alarm>\n");
struct tm *alarmTime = localtime(&(timer->alarmTime));
hh->WriteLn("\t\t\t\t<normal>\n");
_SendTime(hh, alarmTime, (int)timer->alarmTime);
hh->WriteLn("\t\t\t\t</normal>\n");
time_t real_alarmTimeT = timer->alarmTime - pre;
struct tm *safetyAlarmTime = localtime(&real_alarmTimeT);
hh->WriteLn("\t\t\t\t<safety>\n");
_SendTime(hh, safetyAlarmTime, (int)real_alarmTimeT);
hh->WriteLn("\t\t\t\t</safety>\n");
hh->WriteLn("\t\t\t</alarm>\n");
// announcetime
hh->WriteLn("\t\t\t<announce>\n");
struct tm *announceTime = localtime(&(timer->announceTime));
hh->WriteLn("\t\t\t\t<normal>\n");
_SendTime(hh, announceTime, (int)timer->announceTime);
hh->WriteLn("\t\t\t\t</normal>\n");
time_t real_announceTimeT = timer->announceTime - pre;
struct tm *safetyAnnounceTime = localtime(&real_announceTimeT);
hh->WriteLn("\t\t\t\t<safety>\n");
_SendTime(hh, safetyAnnounceTime, (int)real_announceTimeT);
hh->WriteLn("\t\t\t\t</safety>\n");
hh->WriteLn("\t\t\t</announce>\n");
// stoptime
if(timer->stopTime > 0) {
hh->WriteLn("\t\t\t<stop>\n");
struct tm *stopTime = localtime(&(timer->stopTime));
hh->WriteLn("\t\t\t\t<normal>\n");
_SendTime(hh, stopTime, (int)timer->stopTime);
hh->WriteLn("\t\t\t\t</normal>\n");
time_t real_stopTimeT = timer->stopTime - post;
struct tm *safetyStopTime = localtime(&real_stopTimeT);
hh->WriteLn("\t\t\t\t<safety>\n");
_SendTime(hh, safetyStopTime, (int)real_stopTimeT);
hh->WriteLn("\t\t\t\t</safety>\n");
hh->WriteLn("\t\t\t</stop>\n");
}
// repeat
std::string zRep = NeutrinoAPI->timerEventRepeat2Str(timer->eventRepeat);
std::string zRepCount;
if (timer->eventRepeat == CTimerd::TIMERREPEAT_ONCE)
zRepCount = "-";
else
zRepCount = (timer->repeatCount == 0) ? "&#x221E;" : string_printf("%dx",timer->repeatCount);
hh->WriteLn("\t\t\t<repeat>\n");
hh->printf("\t\t\t\t<count>%s</count>\n",zRepCount.c_str());
hh->printf("\t\t\t\t<number>%d</number>\n",(int)timer->eventRepeat);
hh->printf("\t\t\t\t<text>%s</text>\n",zRep.c_str());
std::string weekdays;
NeutrinoAPI->Timerd->setWeekdaysToStr(timer->eventRepeat, weekdays);
hh->printf("\t\t\t\t<weekdays>%s</weekdays>\n", weekdays.c_str());
hh->WriteLn("\t\t\t</repeat>\n");
// channel infos
std::string channel_name = NeutrinoAPI->GetServiceName(timer->channel_id);
if (channel_name.empty())
channel_name = CServiceManager::getInstance()->IsChannelTVChannel(timer->channel_id) ? "Unknown TV-Channel" : "Unknown Radio-Channel";
// epg title
std::string title = timer->epgTitle;
if(timer->epgID!=0) {
CEPGData epgdata;
if (CEitManager::getInstance()->getEPGid(timer->epgID, timer->epg_starttime, &epgdata))
title = epgdata.title;
}
// timer specific data
switch(timer->eventType)
{
#if 0
case CTimerd::TIMER_NEXTPROGRAM : {
hh->printf("\t\t\t<channel_id>" PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS "</channel_id>\n",timer->channel_id);
hh->printf("\t\t\t<channel_name>%s</channel_name>\n",channel_name.c_str());
hh->printf("\t\t\t<title>%s</title>\n",title.c_str());
}
break;
#endif
case CTimerd::TIMER_ZAPTO : {
hh->printf("\t\t\t<channel_id>" PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS "</channel_id>\n",timer->channel_id);
hh->printf("\t\t\t<channel_name>%s</channel_name>\n",channel_name.c_str());
hh->printf("\t\t\t<title>%s</title>\n",title.c_str());
}
break;
case CTimerd::TIMER_RECORD : {
hh->printf("\t\t\t<channel_id>" PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS "</channel_id>\n",timer->channel_id);
hh->printf("\t\t\t<channel_name>%s</channel_name>\n",channel_name.c_str());
hh->printf("\t\t\t<title>%s</title>\n",title.c_str());
// audio
if(timer->apids != TIMERD_APIDS_CONF) {
hh->WriteLn("\t\t\t<audio>\n");
hh->WriteLn("\t\t\t\t<apids_conf>false</apids_conf>\n");
if(timer->apids & TIMERD_APIDS_STD)
hh->WriteLn("\t\t\t\t<apids_std>true</apids_std>\n");
else
hh->WriteLn("\t\t\t\t<apids_std>false</apids_std>\n");
if(timer->apids & TIMERD_APIDS_ALT)
hh->WriteLn("\t\t\t\t<apids_alt>true</apids_alt>\n");
else
hh->WriteLn("\t\t\t\t<apids_alt>false</apids_alt>\n");
if(timer->apids & TIMERD_APIDS_AC3)
hh->WriteLn("\t\t\t\t<apids_ac3>true</apids_ac3>\n");
else
hh->WriteLn("\t\t\t\t<apids_ac3>false</apids_ac3>\n");
hh->WriteLn("\t\t\t</audio>\n");
}
else {
hh->WriteLn("\t\t\t<audio>\n");
hh->WriteLn("\t\t\t\t<apids_conf>true</apids_conf>\n");
hh->WriteLn("\t\t\t\t<apids_std>false</apids_std>\n");
hh->WriteLn("\t\t\t\t<apids_alt>false</apids_alt>\n");
hh->WriteLn("\t\t\t\t<apids_ac3>false</apids_ac3>\n");
hh->WriteLn("\t\t\t</audio>\n");
}
hh->printf("\t\t\t<recording_dir>%s</recording_dir>\n",timer->recordingDir);
hh->printf("\t\t\t<epg_id>%d</epg_id>\n",(int)timer->epgID);
}
break;
case CTimerd::TIMER_STANDBY : {
hh->printf("\t\t\t<status>%s</status>\n",(timer->standby_on)? "on" : "off");
}
break;
case CTimerd::TIMER_REMIND : {
std::string _message;
_message = std::string(timer->message).substr(0,20);
hh->printf("\t\t\t<message>%s</message>\n",_message.c_str());
}
break;
case CTimerd::TIMER_EXEC_PLUGIN : {
hh->printf("\t\t\t<plugin>%s</plugin>\n",timer->pluginName);
}
break;
case CTimerd::TIMER_SLEEPTIMER : {
}
break;
case CTimerd::TIMER_IMMEDIATE_RECORD : {
}
break;
default:
{}
}
hh->WriteLn("\t\t</timer>\n");
}
hh->WriteLn("\t</timer_list>\n");
hh->WriteLn("</timer>\n");
}
//-----------------------------------------------------------------------------
// yweb : Extentions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Dispatcher
//-----------------------------------------------------------------------------
void CControlAPI::YWebCGI(CyhookHandler *hh)
{
bool status=true;
if (!hh->ParamList["video_stream_pids"].empty())
{
int para=0;
sscanf( hh->ParamList["video_stream_pids"].c_str(), "%d", &para);
YWeb_SendVideoStreamingPids(hh, para);
}
else if (hh->ParamList["1"] == "radio_stream_pid")
YWeb_SendRadioStreamingPid(hh);
if(!status)
hh->SendError();
}
//-----------------------------------------------------------------------------
// Get Streaming Pids 0x$pmt,0x$vpid,0x$apid with apid_no is the Number of Audio-Pid
//-----------------------------------------------------------------------------
void CControlAPI::YWeb_SendVideoStreamingPids(CyhookHandler *hh, int apid_no)
{
CZapitClient::responseGetPIDs pids;
int apid=0,apid_idx=0;
pids.PIDs.vpid=0;
NeutrinoAPI->Zapit->getPIDS(pids);
if( apid_no < (int)pids.APIDs.size())
apid_idx=apid_no;
if(!pids.APIDs.empty())
apid = pids.APIDs[apid_idx].pid;
if(!hh->ParamList["no_commas"].empty())
{
hh->printf("0x%04x 0x%04x 0x%04x",pids.PIDs.pmtpid,pids.PIDs.vpid,apid);
if (pids.PIDs.pcrpid != pids.PIDs.vpid)
hh->printf(" 0x%04x", pids.PIDs.pcrpid);
}
else
{
hh->printf("0x%04x,0x%04x,0x%04x",pids.PIDs.pmtpid,pids.PIDs.vpid,apid);
if (pids.PIDs.pcrpid != pids.PIDs.vpid)
hh->printf(",0x%04x", pids.PIDs.pcrpid);
}
}
//-----------------------------------------------------------------------------
// Get Streaming Pids 0x$pmt,0x$vpid,0x$apid with apid_no is the Number of Audio-Pid
//-----------------------------------------------------------------------------
void CControlAPI::YWeb_SendRadioStreamingPid(CyhookHandler *hh)
{
CZapitClient::responseGetPIDs pids;
int apid=0;
NeutrinoAPI->Zapit->getPIDS(pids);
if(!pids.APIDs.empty())
apid = pids.APIDs[0].pid;
hh->printf("0x%04x",apid);
}
//-----------------------------------------------------------------------------
void CControlAPI::doModifyTimer(CyhookHandler *hh)
{
hh->ParamList["update"]="1";
doNewTimer(hh);
}
//-------------------------------------------------------------------------
void CControlAPI::doNewTimer(CyhookHandler *hh)
{
time_t announceTimeT = 0,
stopTimeT = 0,
alarmTimeT = 0,
tnull = 0;
unsigned int repCount = 0;
int alHour=0;
// if alarm given then in parameters im time_t format
if(!hh->ParamList["alarm"].empty())
{
alarmTimeT = atoi(hh->ParamList["alarm"].c_str());
if(!hh->ParamList["stop"].empty())
stopTimeT = atoi(hh->ParamList["stop"].c_str());
if(!hh->ParamList["announce"].empty())
announceTimeT = atoi(hh->ParamList["announce"].c_str());
else
announceTimeT = alarmTimeT;
}
else if(!hh->ParamList["alDate"].empty()) //given formatted
{
// Alarm Date - Format exact! DD.MM.YYYY
tnull = time(NULL);
struct tm *alarmTime=localtime(&tnull);
alarmTime->tm_sec = 0;
if(sscanf(hh->ParamList["alDate"].c_str(),"%2d.%2d.%4d",&(alarmTime->tm_mday), &(alarmTime->tm_mon), &(alarmTime->tm_year)) == 3)
{
alarmTime->tm_mon -= 1;
alarmTime->tm_year -= 1900;
}
// Alarm Time - Format exact! HH:MM
if(!hh->ParamList["alTime"].empty())
sscanf(hh->ParamList["alTime"].c_str(),"%2d.%2d",&(alarmTime->tm_hour), &(alarmTime->tm_min));
alHour = alarmTime->tm_hour;
correctTime(alarmTime);
alarmTimeT = mktime(alarmTime);
announceTimeT = alarmTimeT;
struct tm *stopTime = localtime(&alarmTimeT);
stopTime->tm_sec = 0;
// Stop Time - Format exact! HH:MM
if(!hh->ParamList["stTime"].empty())
sscanf(hh->ParamList["stTime"].c_str(),"%2d.%2d",&(stopTime->tm_hour), &(stopTime->tm_min));
// Stop Date - Format exact! DD.MM.YYYY
if(!hh->ParamList["stDate"].empty())
if(sscanf(hh->ParamList["stDate"].c_str(),"%2d.%2d.%4d",&(stopTime->tm_mday), &(stopTime->tm_mon), &(stopTime->tm_year)) == 3)
{
stopTime->tm_mon -= 1;
stopTime->tm_year -= 1900;
}
correctTime(stopTime);
stopTimeT = mktime(stopTime);
if(hh->ParamList["stDate"].empty() && alHour > stopTime->tm_hour)
stopTimeT += 24* 60 * 60; // add 1 Day
}
else // alarm/stop time given in pieces
{
// alarm time
time_t now = time(NULL);
struct tm *alarmTime=localtime(&now);
if(!hh->ParamList["ad"].empty())
alarmTime->tm_mday = atoi(hh->ParamList["ad"].c_str());
if(!hh->ParamList["amo"].empty())
alarmTime->tm_mon = atoi(hh->ParamList["amo"].c_str())-1;
if(!hh->ParamList["ay"].empty())
alarmTime->tm_year = atoi(hh->ParamList["ay"].c_str())-1900;
if(!hh->ParamList["ah"].empty())
alarmTime->tm_hour = atoi(hh->ParamList["ah"].c_str());
if(!hh->ParamList["ami"].empty())
alarmTime->tm_min = atoi(hh->ParamList["ami"].c_str());
alarmTime->tm_sec = 0;
correctTime(alarmTime);
alarmTimeT = mktime(alarmTime);
announceTimeT = alarmTimeT;
// stop time
struct tm *stopTime = alarmTime;
if(!hh->ParamList["sd"].empty())
stopTime->tm_mday = atoi(hh->ParamList["sd"].c_str());
if(!hh->ParamList["smo"].empty())
stopTime->tm_mon = atoi(hh->ParamList["smo"].c_str())-1;
if(!hh->ParamList["sy"].empty())
stopTime->tm_year = atoi(hh->ParamList["sy"].c_str())-1900;
if(!hh->ParamList["sh"].empty())
stopTime->tm_hour = atoi(hh->ParamList["sh"].c_str());
if(!hh->ParamList["smi"].empty())
stopTime->tm_min = atoi(hh->ParamList["smi"].c_str());
stopTime->tm_sec = 0;
correctTime(stopTime);
stopTimeT = mktime(stopTime);
}
if(announceTimeT != 0)
announceTimeT -= 60;
CTimerd::CTimerEventTypes type;
if(!hh->ParamList["type"].empty())
type = (CTimerd::CTimerEventTypes) atoi(hh->ParamList["type"].c_str());
else // default is: record
type = CTimerd::TIMER_RECORD;
// repeat
if(!hh->ParamList["repcount"].empty())
{
repCount = atoi(hh->ParamList["repcount"].c_str());
}
CTimerd::CTimerEventRepeat rep;
if(!hh->ParamList["rep"].empty())
rep = (CTimerd::CTimerEventRepeat) atoi(hh->ParamList["rep"].c_str());
else // default: no repeat
rep = (CTimerd::CTimerEventRepeat)0;
if(((int)rep) >= ((int)CTimerd::TIMERREPEAT_WEEKDAYS) && !hh->ParamList["wd"].empty())
NeutrinoAPI->Timerd->getWeekdaysFromStr(&rep, hh->ParamList["wd"]);
// apids
bool changeApids=false;
unsigned char apids=0;
if(hh->ParamList["apcf"] == "on")
{
changeApids=true;
apids=0;
}
else
{
if(hh->ParamList["apst"] == "on")
{
changeApids=true;
apids |= TIMERD_APIDS_STD;
}
if(hh->ParamList["apal"] == "on")
{
changeApids=true;
apids |= TIMERD_APIDS_ALT;
}
if(hh->ParamList["apac"] == "on")
{
changeApids=true;
apids |= TIMERD_APIDS_AC3;
}
}
CTimerd::RecordingInfo recinfo;
CTimerd::EventInfo eventinfo;
eventinfo.epgID = 0;
eventinfo.epg_starttime = 0;
eventinfo.apids = TIMERD_APIDS_CONF;
eventinfo.recordingSafety = (hh->ParamList["rs"] == "1");
// channel by Id or name
if(!hh->ParamList["channel_id"].empty())
sscanf(hh->ParamList["channel_id"].c_str(),
SCANF_CHANNEL_ID_TYPE,
&eventinfo.channel_id);
else
eventinfo.channel_id = NeutrinoAPI->ChannelNameToChannelId(hh->ParamList["channel_name"]);
std::string _rec_dir = hh->ParamList["rec_dir"];
void *data=NULL;
if(type == CTimerd::TIMER_RECORD)
announceTimeT-=120;
if(type == CTimerd::TIMER_STANDBY)
{
bool standby_on = (hh->ParamList["sbon"]=="1");
data=&standby_on;
}
/* else if(type==CTimerd::TIMER_NEXTPROGRAM || type==CTimerd::TIMER_ZAPTO) */
else if (type == CTimerd::TIMER_ZAPTO)
data= &eventinfo;
else if (type==CTimerd::TIMER_RECORD)
{
if(_rec_dir.empty())
{
// get Default Recordingdir
CConfigFile *Config = new CConfigFile(',');
Config->loadConfig(NEUTRINO_CONFIGFILE);
_rec_dir = Config->getString("network_nfs_recordingdir", "/mnt/filme");
delete Config;
}
if(changeApids)
eventinfo.apids = apids;
recinfo = eventinfo;
strncpy(recinfo.recordingDir, _rec_dir.c_str(), RECORD_DIR_MAXLEN-1);
data = &recinfo;
}
else if(type==CTimerd::TIMER_REMIND)
{
char msg[REMINDER_MESSAGE_MAXLEN];
memset(msg, 0, sizeof(msg));
strncpy(msg, hh->ParamList["msg"].c_str(),REMINDER_MESSAGE_MAXLEN-1);
data=msg;
}
else if(type==CTimerd::TIMER_EXEC_PLUGIN)
{
char msg[EXEC_PLUGIN_NAME_MAXLEN];
memset(msg, 0, sizeof(msg));
strncpy(msg, hh->ParamList["PluginName"].c_str(),EXEC_PLUGIN_NAME_MAXLEN-1);
data=msg;
}
// update or add timer
if(hh->ParamList["update"]=="1")
{
if(!hh->ParamList["id"].empty())
{
unsigned modyId = atoi(hh->ParamList["id"].c_str());
if(type == CTimerd::TIMER_RECORD)
NeutrinoAPI->Timerd->modifyRecordTimerEvent(modyId, announceTimeT, alarmTimeT, stopTimeT, rep,repCount,_rec_dir.c_str());
else
NeutrinoAPI->Timerd->modifyTimerEvent(modyId, announceTimeT, alarmTimeT, stopTimeT, rep,repCount);
// NeutrinoAPI->Timerd->removeTimerEvent(modyId);
if(changeApids)
NeutrinoAPI->Timerd->modifyTimerAPid(modyId,apids);
}
else
{
CTimerd::TimerList timerlist;
timerlist.clear();
NeutrinoAPI->Timerd->getTimerList(timerlist);
CTimerd::TimerList::iterator timer = timerlist.begin();
// Look for Recording Safety Timers too
time_t real_alarmTimeT = alarmTimeT;
if(eventinfo.recordingSafety)
{
int pre,post;
NeutrinoAPI->Timerd->getRecordingSafety(pre,post);
real_alarmTimeT -= pre;
}
for(; timer != timerlist.end();++timer)
if(timer->alarmTime == real_alarmTimeT)
{
NeutrinoAPI->Timerd->removeTimerEvent(timer->eventID);
break;
}
NeutrinoAPI->Timerd->addTimerEvent(type,data,announceTimeT,alarmTimeT,stopTimeT,rep,repCount);
}
}
else
NeutrinoAPI->Timerd->addTimerEvent(type,data,announceTimeT,alarmTimeT,stopTimeT,rep,repCount);
hh->SendOk();
}
//-------------------------------------------------------------------------
void CControlAPI::setBouquetCGI(CyhookHandler *hh)
{
if (!hh->ParamList["selected"].empty()) {
int selected = atoi(hh->ParamList["selected"].c_str());
if(hh->ParamList["action"].compare("hide") == 0)
NeutrinoAPI->Zapit->setBouquetHidden(selected - 1,true);
else if(hh->ParamList["action"].compare("show") == 0)
NeutrinoAPI->Zapit->setBouquetHidden(selected - 1,false);
else if(hh->ParamList["action"].compare("lock") == 0)
NeutrinoAPI->Zapit->setBouquetLock(selected - 1,true);
else if(hh->ParamList["action"].compare("unlock") == 0)
NeutrinoAPI->Zapit->setBouquetLock(selected - 1,false);
hh->SendOk();
}
else
hh->SendError();
}
//-------------------------------------------------------------------------
void CControlAPI::saveBouquetCGI(CyhookHandler *hh)
{
NeutrinoAPI->Zapit->saveBouquets();
NeutrinoAPI->UpdateBouquets();
hh->SendOk();
}
//-------------------------------------------------------------------------
void CControlAPI::moveBouquetCGI(CyhookHandler *hh)
{
if (!hh->ParamList["selected"].empty() && (
hh->ParamList["action"] == "up" ||
hh->ParamList["action"] == "down"))
{
int selected = atoi(hh->ParamList["selected"].c_str());
if (hh->ParamList["action"] == "up") {
NeutrinoAPI->Zapit->moveBouquet(selected - 1, (selected - 1) - 1);
selected--;
} else {
NeutrinoAPI->Zapit->moveBouquet(selected - 1, (selected + 1) - 1);
selected++;
}
hh->SendOk();
}
else
hh->SendError();
}
//-------------------------------------------------------------------------
void CControlAPI::deleteBouquetCGI(CyhookHandler *hh)
{
if (!hh->ParamList["selected"].empty()) {
int selected = atoi(hh->ParamList["selected"].c_str());
NeutrinoAPI->Zapit->deleteBouquet(selected - 1);
hh->SendOk();
}
else
hh->SendError();
}
//-------------------------------------------------------------------------
void CControlAPI::addBouquetCGI(CyhookHandler *hh)
{
if (!hh->ParamList["name"].empty())
{
std::string tmp = hh->ParamList["name"];
if (NeutrinoAPI->Zapit->existsBouquet(tmp.c_str()) == -1)
{
NeutrinoAPI->Zapit->addBouquet(tmp.c_str());
hh->SendOk();
}
else
hh->SendError();
}
}
//-------------------------------------------------------------------------
void CControlAPI::renameBouquetCGI(CyhookHandler *hh)
{
if (!hh->ParamList["selected"].empty())
{
if (!hh->ParamList["nameto"].empty())
{
if (NeutrinoAPI->Zapit->existsBouquet((hh->ParamList["nameto"]).c_str()) == -1)
{
NeutrinoAPI->Zapit->renameBouquet(atoi(hh->ParamList["selected"].c_str()) - 1, hh->ParamList["nameto"].c_str());
hh->SendOk();
return;
}
}
}
hh->SendError();
}
//-------------------------------------------------------------------------
void CControlAPI::changeBouquetCGI(CyhookHandler *hh)
{
if (!(hh->ParamList["selected"].empty()))
{
int selected = atoi(hh->ParamList["selected"].c_str());
CZapitClient::BouquetChannelList BChannelList;
NeutrinoAPI->Zapit->getBouquetChannels(selected - 1, BChannelList, CZapitClient::MODE_CURRENT, true);
CZapitClient::BouquetChannelList::iterator channels = BChannelList.begin();
for(; channels != BChannelList.end(); ++channels)
{
NeutrinoAPI->Zapit->removeChannelFromBouquet(selected - 1, channels->channel_id);
}
t_channel_id channel_id;
int delta;
const char * bchannels = hh->ParamList["bchannels"].c_str();
while (sscanf(bchannels,
SCANF_CHANNEL_ID_TYPE
"%n",
&channel_id,
&delta) > 0)
{
NeutrinoAPI->Zapit->addChannelToBouquet(selected - 1, channel_id);
bchannels += (delta + 1); // skip the separating ',', too
}
NeutrinoAPI->Zapit->renumChannellist();
NeutrinoAPI->UpdateBouquets();
if(!hh->ParamList["redirect"].empty())
hh->SendRewrite(hh->ParamList["redirect"]);
else
hh->SendOk();
}
else
hh->SendError();
}
//-------------------------------------------------------------------------
void CControlAPI::updateBouquetCGI(CyhookHandler *hh)
{
NeutrinoAPI->UpdateBouquets();
hh->SendOk();
}
//-------------------------------------------------------------------------
// audio_no : (optional) audio channel
// host : (optional) ip of dbox
void CControlAPI::build_live_url(CyhookHandler *hh)
{
std::string xpids;
int mode = NeutrinoAPI->Zapit->getMode();
if ( mode == CZapitClient::MODE_TV)
{
CZapitClient::responseGetPIDs pids;
int apid=0,apid_no=0,apid_idx=0;
pids.PIDs.vpid=0;
if(!hh->ParamList["audio_no"].empty())
apid_no = atoi(hh->ParamList["audio_no"].c_str());
NeutrinoAPI->Zapit->getPIDS(pids);
if( apid_no < (int)pids.APIDs.size())
apid_idx=apid_no;
if(!pids.APIDs.empty())
apid = pids.APIDs[apid_idx].pid;
xpids = string_printf("0x%04x,0x%04x,0x%04x",pids.PIDs.pmtpid,pids.PIDs.vpid,apid);
if (pids.PIDs.pcrpid != pids.PIDs.vpid)
xpids += string_printf(",0x%04x", pids.PIDs.pcrpid);
}
else if ( mode == CZapitClient::MODE_RADIO)
{
CZapitClient::responseGetPIDs pids;
int apid=0;
NeutrinoAPI->Zapit->getPIDS(pids);
if(!pids.APIDs.empty())
apid = pids.APIDs[0].pid;
//xpids = string_printf("0x%04x",apid);
xpids = string_printf("0x%04x,0x%04x",pids.PIDs.pmtpid,apid);
}
else
hh->SendError();
// build url
std::string url = "";
if(!hh->ParamList["host"].empty())
url = "http://"+hh->ParamList["host"];
else
url = "http://"+hh->HeaderList["Host"];
/* strip off optional custom port */
if (url.rfind(":") != 4)
url = url.substr(0, url.rfind(":"));
//url += (mode == CZapitClient::MODE_TV) ? ":31339/0," : ":31338/";
url += ":31339/0,";
url += xpids;
// response url
if(!hh->ParamList["vlc_link"].empty())
{
write_to_file("/tmp/vlc.m3u", url);
hh->SendRedirect("/tmp/vlc.m3u");
}
else
{
hh->SetHeader(HTTP_OK, "text/html; charset=UTF-8");
hh->Write(url);
}
}
//-------------------------------------------------------------------------
void CControlAPI::logoCGI(CyhookHandler *hh)
{
t_channel_id channel_id;
sscanf(hh->ParamList["1"].c_str(),
SCANF_CHANNEL_ID_TYPE,
&channel_id);
hh->Write(NeutrinoAPI->getLogoFile(hh->WebserverConfigList["Tuxbox.LogosURL"], channel_id));
}
//-------------------------------------------------------------------------
/** Get Config File or save values to given config file
* @param hh CyhookHandler
*
* @par nhttpd-usage
* @code
* /control/config?config=neutrino|nhttpd|yweb[&action=submit&key1=value1&key2=value2&...][&format=|xml|json]
* @endcode
*
* @par example:
* @code
* /control/config?config=neutrino
* /control/config?config=neutrino&format=json
* /control/config?config=neutrino&action=submit&epg_dir=/media/sda1/epg
* @endcode
*
* @par output (json)
* /control/config?config=neutrino&format=json
* @code
* {"success": "true", "data":{"analog_mode1": "16",
* "analog_mode2": "1",
* [...snip...]
* "zap_cycle": "0",
* "zapto_pre_time": "0",
* }}
* @endcode
*
* @par output (plain)
* /control/config?config=neutrino
* @code
* analog_mode1=16
* analog_mode2=1
* [...snip...]
* zap_cycle=0
* zapto_pre_time=0
* @endcode
*
* @par output (xml)
* /control/config?config=neutrino&format=xml
* @code
* <config>
* <analog_mode1>16</analog_mode1>
* <analog_mode2>1</analog_mode2>
* [...snip...]
* <zap_cycle>0</zap_cycle>
* <zapto_pre_time>0</zapto_pre_time>
* </config>
* @endcode
*/
//-------------------------------------------------------------------------
void CControlAPI::ConfigCGI(CyhookHandler *hh) {
bool load = true;
CConfigFile *Config = new CConfigFile(',');
ConfigDataMap conf;
std::string config_filename = "";
std::string error = "";
std::string result = "";
std::string configFileName = hh->ParamList["config"];
hh->outStart();
if (hh->ParamList["action"] == "submit")
load = false;
// Para "config" describes the config type
if (configFileName == "neutrino")
config_filename = NEUTRINO_CONFIGFILE;
else if (configFileName == "moviebrowser")
config_filename = MOVIEBROWSER_CONFIGFILE;
else if (configFileName == "nhttpd")
config_filename = HTTPD_CONFIGFILE;
else if (configFileName == "yweb")
config_filename = YWEB_CONFIGFILE;
if (!config_filename.empty()) {
Config->loadConfig(config_filename);
if (load) { // get and output list
conf = Config->getConfigDataMap();
ConfigDataMap::iterator it, end, start;
for (start = conf.begin(), it=start, end = conf.end(); it != end; ++it) {
std::string key = it->first;
replace(key, ".", "_dot_");
replace(key, "-", "_bind_");
if (!(hh->ParamList["config"] == "nhttpd" && it->first == "mod_auth.password")) {
if(it != start)
result += hh->outNext();
result += hh->outPair(key, it->second, false);
}
}
}
else { // set values and save list
for (CStringList::iterator it = hh->ParamList.begin(); it != hh->ParamList.end(); ++it) {
std::string key = it->first;
replace(key, "_dot_", ".");
replace(key, "_bind_", "-");
if (key != "_dc" && key != "action" && key != "format" && key != "config") {
Config->setString(key, it->second);
}
}
if (!config_filename.empty())
Config->saveConfig(config_filename);
}
}
else {
if(!configFileName.empty())
error = string_printf("no config defined for %s", (hh->ParamList["config"]).c_str());
}
hh->WriteLn(hh->outObject("config", result));
if (error.empty())
hh->SendResult(result);
else
hh->SendError(error);
delete Config;
}
//-----------------------------------------------------------------------------
/** Get a list of files with attributtes for a given path
*
* @param hh CyhookHandler
*
* @par nhttpd-usage
* @code
* /control/file?action=list&path={path}[&format=|xml|json][&sort=false]
* @endcode
*
* @par example:
* @code
* /control/file?action=list&path=/
* /control/file?action=list&path=/&format=json
* /control/file?action=list&path=/&format=json&sort=false
* @endcode
*
* @par output
* @code
* {"success": "true", "data":{"filelist": [{"name": "timeshift",
* "type_str": "dir",
* "type": "4",
* "fullname": "/timeshift",
* "mode": "41ffld",
* "nlink": "2",
* "user": "root",
* "group": "root",
* "size": "1024",
* "time": "Sun Sep 4 07:38:10 2011",
* "time_t": "1315114690"
* },
* @endcode
* ... snip ...
* @code
* {"name": "root",
* "type_str": "dir",
* "type": "4",
* "fullname": "/root",
* "mode": "41edld",
* "nlink": "2",
* "user": "1000",
* "group": "1000",
* "size": "1024",
* "time": "Wed Aug 31 12:09:29 2011",
* "time_t": "1314785369"
* },
* ]
* }}
* @endcode
*
* @par Not implemented now:
* action =new_folder|delete|read_file|write_file|set_properties
*/
//-----------------------------------------------------------------------------
void CControlAPI::FileCGI(CyhookHandler *hh) {
std::string result = "";
if (hh->ParamList["action"] == "list") { // directory list: action=list&path=<path>
DIR *dirp;
hh->outStart();
std::string path = hh->ParamList["path"];
if ((dirp = opendir(path.c_str()))) {
struct dirent *entry;
std::vector<FileCGI_List> filelist;
while ((entry = readdir(dirp))) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
continue;
std::string ftype;
if (entry->d_type == DT_DIR)
ftype = "dir";
else if (entry->d_type == DT_LNK)
ftype = "lnk";
else if (entry->d_type == 8)
ftype = "file";
if (path[path.length() - 1] != '/')
path += "/";
std::string fullname = path + entry->d_name;
FileCGI_List listitem;
listitem.name = std::string(entry->d_name);
listitem.type_str = ftype;
listitem.type = entry->d_type;
listitem.fullname = fullname;
filelist.push_back(listitem);
}
closedir(dirp);
if (hh->ParamList["sort"] != "false")
sort(filelist.begin(), filelist.end(), fsort);
for(std::vector<FileCGI_List>::iterator f = filelist.begin(); f != filelist.end(); ++f)
{
bool got_next = (f != filelist.end()-1);
std::string item = "";
item += hh->outPair("name", hh->outValue(f->name.c_str()), true);
item += hh->outPair("type_str", hh->outValue(f->type_str.c_str()), true);
item += hh->outPair("type", string_printf("%d", (int) f->type), true);
item += hh->outPair("fullname", hh->outValue(f->fullname.c_str()), true);
struct stat statbuf;
if (stat(f->fullname.c_str(), &statbuf) != -1) {
item += hh->outPair("mode", string_printf("%xld", (long) statbuf.st_mode), true);
/* Print out type, permissions, and number of links. */
//TODO: hh->printf("\t\t<permission>%10.10s</permission>\n", sperm (statbuf.st_mode));
item += hh->outPair("nlink", string_printf("%d", statbuf.st_nlink), true);
/* Print out owner's name if it is found using getpwuid(). */
struct passwd *pwd;
if ((pwd = getpwuid(statbuf.st_uid)) != NULL)
item += hh->outPair("user", pwd->pw_name, true);
else
item += hh->outPair("user", string_printf("%d", statbuf.st_uid), true);
/* Print out group name if it is found using getgrgid(). */
struct group *grp;
if ((grp = getgrgid(statbuf.st_gid)) != NULL)
item += hh->outPair("group", grp->gr_name, true);
else
item += hh->outPair("group", string_printf("%d", statbuf.st_gid), true);
/* Print size of file. */
item += hh->outPair("size", string_printf("%jd", (intmax_t) statbuf.st_size), true);
struct tm *tm = localtime(&statbuf.st_mtime);
char datestring[256] = {0};
/* Get localized date string. */
strftime(datestring, sizeof(datestring), nl_langinfo(D_T_FMT), tm);
item += hh->outPair("time", hh->outValue(datestring), true);
item += hh->outPair("time_t", string_printf("%ld", (long) statbuf.st_mtime), false);
}
result += hh->outArrayItem("item", item, got_next);
}
}
result = hh->outArray("filelist", result);
hh->SendResult(result);
}
// create new folder
else if (hh->ParamList["action"] == "new_folder") {
hh->SetHeader(HTTP_OK, "text/plain; charset=UTF-8");
//TODO
}
else if (hh->ParamList["action"] == "delete") {
hh->SetHeader(HTTP_OK, "text/plain; charset=UTF-8");
//TODO
}
}
//-----------------------------------------------------------------------------
/** Get a list of statfs output for a given path
*
* @param hh CyhookHandler
*
* @par nhttpd-usage
* @code
* /control/statfs[?path={path}][&format=plain|xml|json]
* @endcode
*
* @par example:
* @code
* /control/statfs
* /control/statfs?path=/media/sda1/movies&format=json
* @endcode
*
* @par output
* @code
* {"success": "true", "data":
* {
* "statfs": {
* "path": "/media/sda1/movies",
* "f_type": "0x4d44",
* "f_bsize": "4096",
* "f_blocks": "488444",
* "f_bfree": "365874",
* "f_bavail": "365874",
* "f_files": "0",
* "f_ffree": "0",
* "f_fsid": "0x801, 0",
* "f_namelen": "1530",
* "f_frsize": "24"
* }
* }}
* @endcode
*/
//-----------------------------------------------------------------------------
void CControlAPI::StatfsCGI(CyhookHandler *hh) {
std::string result = "";
if (hh->ParamList["path"].empty())
hh->ParamList["path"] = "/";
hh->outStart();
std::string path = hh->ParamList["path"];
struct statfs s;
if (::statfs(path.c_str(), &s) == 0)
{
std::string item = "";
item += hh->outPair("path", path.c_str(), true);
item += hh->outPair("f_type", string_printf("%#lx", (unsigned long) s.f_type), true);
item += hh->outPair("f_bsize", string_printf("%lu", (unsigned long) s.f_bsize), true);
item += hh->outPair("f_blocks", string_printf("%lu", (unsigned long) s.f_blocks), true);
item += hh->outPair("f_bfree", string_printf("%lu", (unsigned long) s.f_bfree), true);
item += hh->outPair("f_bavail", string_printf("%lu", (unsigned long) s.f_bavail), true);
item += hh->outPair("f_files", string_printf("%lu", (unsigned long) s.f_files), true);
item += hh->outPair("f_ffree", string_printf("%lu", (unsigned long) s.f_ffree), true);
item += hh->outPair("f_fsid", string_printf("%#x, %#x", (unsigned) s.f_fsid.__val[0], (unsigned) s.f_fsid.__val[1]), true);
item += hh->outPair("f_namelen", string_printf("%lu", (unsigned long) s.f_namelen), true);
item += hh->outPair("f_frsize", string_printf("%lu", (unsigned long) s.f_frsize), false);
result = hh->outObject("statfs", item);
hh->SendResult(result);
}
else
hh->SendError("statfs failed");
}
//-----------------------------------------------------------------------------
/** Get neutrino directories
*
* @param hh CyhookHandler
*
* @par nhttpd-usage
* @code
* /control/getdir?dir=allmoviedirs&[&subdirs=true][&format=|xml|json]
* @endcode
*
{"success": "true", "data":{"dirs": [{"dir": "/mnt/series/",
"used": "1"
}
,{"dir": "/mnt/movies/",
"used": "1"
}
,{"dir": "/mnt/movies/subdir"
}
{"dir": "/media/sda1/movie"
}
,]
}}
* @endcode
*
*/
//-----------------------------------------------------------------------------
void CControlAPI::getDirCGI(CyhookHandler *hh) {
std::string result = "";
std::string item = "";
bool isFirstLine = true;
hh->outStart(true /*old mode*/);
//Shows all 7 directories stored in the moviebrowser.conf
if (hh->ParamList["dir"] == "moviedir" || hh->ParamList["dir"] == "allmoviedirs" ) {
CConfigFile *Config = new CConfigFile(',');
Config->loadConfig(MOVIEBROWSER_CONFIGFILE);
char index[21];
std::string mb_dir_used;
std::string mb_dir;
for(int i=0;i<8;i++) {
snprintf(index, sizeof(index), "%d", i);
mb_dir = "mb_dir_";
mb_dir = mb_dir + index;
mb_dir = Config->getString(mb_dir, "");
if(!mb_dir.empty()) {
item += hh->outPair("dir", hh->outValue(mb_dir), false);
if(isFirstLine) {
isFirstLine = false;
}
else {
result += hh->outNext();
}
result += hh->outArrayItem("item", item, false);
item = "";
if (hh->ParamList["subdirs"] == "true") {
result = getSubdirectories(hh, mb_dir, result);
}
}
}
}
//Shows the neutrino recording dir
if (hh->ParamList["dir"] == "recordingdir" || hh->ParamList["dir"] == "allmoviedirs" ) {
item += hh->outPair("dir", hh->outValue(g_settings.network_nfs_recordingdir), false);
if(isFirstLine) {
isFirstLine = false;
}
else {
result += hh->outNext();
}
result += hh->outArrayItem("item", item, false);
if (hh->ParamList["subdirs"] == "true") {
result = getSubdirectories(hh, g_settings.network_nfs_recordingdir, result);
}
}
result = hh->outArray("dirs", result);
hh->SendResult(result);
}
//Helpfunction to get subdirs of a dir
std::string CControlAPI::getSubdirectories(CyhookHandler *hh, std::string path, std::string result) {
std::string item = "";
std::string dirname;
DIR *dirp;
struct dirent *entry;
if ((dirp = opendir(path.c_str()))) {
while ((entry = readdir(dirp))) {
if (entry->d_type == DT_DIR && entry->d_name[0] != '.') {
if (path[path.length() - 1] != '/') {
path += "/";
}
std::string fullname = path + entry->d_name;
item += hh->outPair("dir", hh->outValue(fullname), false);
result += hh->outNext();
result += hh->outArrayItem("item", item, false);
item = "";
result = getSubdirectories(hh, fullname, result);
}
}
closedir(dirp);
}
return result;
}