void RemoteResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); if ( request.method() == "OPTIONS" ) { reply.addHeader("Allow", "POST"); reply.httpReturn(200, "OK"); return; } if (request.method() != "POST") { reply.httpReturn(403, "Only POST method is support by the remote control"); return; } if ( (int)request.url().find("/remote/switch") != -1 ) { QueryHandler q("/remote/switch", request); const cChannel* channel = VdrExtension::getChannel(q.getParamAsString(0)); if ( channel == NULL ) { reply.httpReturn(404, "Channel-Id is not valid."); } else { TaskScheduler::get()->SwitchableChannel(channel->GetChannelID()); } return; } if (!keyPairList->hitKey(request, reply)) { reply.httpReturn(404, "Remote Control does not support the requested key."); } }
void SearchTimersResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); cPlugin* plugin = cPluginManager::GetPlugin("epgsearch"); if (plugin == NULL) { reply.httpReturn(403, "Epgsearch isn't installed!"); return; } if ((int)request.url().find("/searchtimers/search/") == 0 ) { replySearch(out, request, reply); } else { if (request.method() == "GET") { replyShow(out, request, reply); } else if (request.method() == "POST") { replyCreate(out, request, reply); } else if (request.method() == "DELETE") { replyDelete(out, request, reply); } else if (request.method() == "OPTIONS") { return; } else { reply.httpReturn(404, "The searchtimer-service does only support the following methods: GET, POST and DELETE."); } } }
void RemoteResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); if (request.method() != "POST") { reply.httpReturn(403, "Only POST method is support by the remote control"); return; } if ( (int)request.url().find("/remote/switch") != -1 ) { QueryHandler q("/remote/switch", request); cChannel* channel = VdrExtension::getChannel(q.getParamAsString(0)); if ( channel == NULL ) { reply.httpReturn(404, "Channel-Id is not valid."); /*} else if ( !Channels.SwitchTo( channel->Number() ) ) { reply.httpReturn(404, "Couldn't switch to channel."); }*/ } else { TaskScheduler::get()->SwitchableChannel(channel->GetChannelID()); } return; } QueryHandler q("/remote", request); string key = q.getParamAsString(0); if (key.length() == 0) { reply.httpReturn(404, "Please add a key to the parameter list, see API-file for more details."); return; } if (!keyPairList->hitKey(key.c_str())) { reply.httpReturn(404, "Remote Control does not support the requested key."); } }
void TimersResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); if ( request.method() == "GET" ) { showTimers(out, request, reply); } else if ( request.method() == "DELETE" ) { deleteTimer(out, request, reply); } else if ( request.method() == "POST" ) { createOrUpdateTimer(out, request, reply, false); } else if ( request.method() == "PUT" ) { createOrUpdateTimer(out, request, reply, true); } else if (request.method() == "OPTIONS") { return; } else { reply.httpReturn(501, "Only GET, DELETE, POST and PUT methods are supported."); } }
void OsdResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler q("/osd", request); if ( request.method() != "GET" ) { reply.httpReturn(403, "Only GET-method is supported!"); return; } BasicOsd* osd = StatusMonitor::get()->getOsd(); if ( osd == NULL ) { if ( q.isFormat(".html") ) { reply.addHeader("Content-Type", "text /html; charset=utf-8"); printEmptyHtml(out); return; } else { reply.httpReturn(404, "No OSD opened!"); return; } } string format = ""; if ( q.isFormat(".json") ) { reply.addHeader("Content-Type", "application/json; charset=utf-8"); format = ".json"; } else if ( q.isFormat(".html") ) { format = ".html"; reply.addHeader("Content-Type", "text/html; charset=utf-8"); } else if ( q.isFormat(".xml") ) { reply.addHeader("Content-Type", "text/xml; charset=utf-8"); format = ".xml"; } else { reply.httpReturn(403, "Resources are not available for the selected format. (Use: .json, .html or .xml)"); return; } int start_filter = q.getOptionAsInt("start"); int limit_filter = q.getOptionAsInt("limit"); switch(osd->Type()) { case 0x01: printTextOsd(out, (TextOsd*)osd, format, start_filter, limit_filter); break; case 0x02: { ChannelOsdWrapper* w = new ChannelOsdWrapper(&out); w->print((ChannelOsd*)osd, format); delete w; } break; case 0x03: { ProgrammeOsdWrapper* w = new ProgrammeOsdWrapper(&out); w->print((ProgrammeOsd*)osd, format); delete w; } break; } }
void ChannelsResponder::reply(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); if ( request.method() != "GET") { reply.httpReturn(403, "To retrieve information use the GET method!"); return; } static cxxtools::Regex imageRegex("/channels/image/*"); static cxxtools::Regex groupsRegex("/channels/groups/*"); if ( imageRegex.match(request.url()) ) { replyImage(out, request, reply); } else if (groupsRegex.match(request.url()) ){ replyGroups(out, request, reply); } else { replyChannels(out, request, reply); } }
void EventsResponder::replyImage(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler q("/events/image", request); if ( request.method() != "GET") { reply.httpReturn(403, "To retrieve information use the GET method!"); return; } StreamExtension se(&out); int eventid = q.getParamAsInt(0); int number = q.getParamAsInt(1); double timediff = -1; vector< string > images; FileCaches::get()->searchEventImages(eventid, images); if (number < 0 || number >= (int)images.size()) { reply.httpReturn(404, "Could not find image because of invalid image number!"); return; } string image = images[number]; string type = image.substr(image.find_last_of(".")+1); string contenttype = (string)"image/" + type; string path = Settings::get()->EpgImageDirectory() + (string)"/" + image; if (request.hasHeader("If-Modified-Since")) { timediff = difftime(FileExtension::get()->getModifiedTime(path), FileExtension::get()->getModifiedSinceTime(request)); } if (timediff > 0.0 || timediff < 0.0) { if ( se.writeBinary(path) ) { reply.addHeader("Content-Type", contenttype.c_str()); FileExtension::get()->addModifiedHeader(path, reply); } else { reply.httpReturn(404, "Could not find image!"); } } else { reply.httpReturn(304, "Not-Modified"); } }
void EventsResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { if ( request.method() == "OPTIONS" ) { reply.addHeader("Allow", "GET, POST"); reply.httpReturn(200, "OK"); return; } QueryHandler::addHeader(reply); if ( (int)request.url().find("/events/image/") == 0 ) { replyImage(out, request, reply); } else if ( (int)request.url().find("/events/search") == 0 ){ replySearchResult(out, request, reply); } else if ( (int)request.url().find("/events/contentdescriptors") == 0 ){ replyContentDescriptors(out, request, reply); } else { replyEvents(out, request, reply); } }
void RecordingsResponder::reply(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); bool found = false; if ((int)request.url().find("/recordings/cut") == 0 ) { if ( request.method() == "GET" ) { showCutterStatus(out, request, reply); } else if (request.method() == "POST") { cutRecording(out, request, reply); } else { reply.httpReturn(501, "Only GET and POST methods are supported by the /recordings/cut service."); } found = true; } else if ((int)request.url().find("/recordings/marks") == 0 ) { if ( request.method() == "DELETE" ) { deleteMarks(out, request, reply); } else if (request.method() == "POST" ) { saveMarks(out, request, reply); } else { reply.httpReturn(501, "Only DELETE and POST methods are supported by the /recordings/marks service."); } found = true; } // original /recordings service else if ((int) request.url().find("/recordings") == 0 ) { if ( request.method() == "GET" ) { showRecordings(out, request, reply); found = true; } else if (request.method() == "DELETE" ) { deleteRecording(out, request,reply); found = true; } else { reply.httpReturn(501, "Only GET and DELETE methods are supported by the /recordings service."); } found = true; } if (!found) { reply.httpReturn(403, "Service not found"); } }
void InfoResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); QueryHandler q("/info", request); if (request.method() != "GET") { reply.httpReturn(403, "Only GET method is support by the remote control"); return; } StreamExtension se(&out); if (q.isFormat(".xml")) { reply.addHeader("Content-Type", "text/xml; charset=utf-8"); replyXml(se); } else if (q.isFormat(".json")) { reply.addHeader("Content-Type", "application/json; charset=utf-8"); replyJson(se); } else if (q.isFormat(".html")) { reply.addHeader("Content-Type", "text/html; charset=utf-8"); replyHtml(se); }else { reply.httpReturn(403, "Support formats: xml, json and html!"); } }
void TimersResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); if ( request.method() == "OPTIONS" ) { reply.addHeader("Allow", "GET, POST, DELETE, PUT"); reply.httpReturn(200, "OK"); return; } if ( request.method() == "GET" ) { showTimers(out, request, reply); } else if ( request.method() == "DELETE" && (int)request.url().find("/timers/bulkdelete") == 0 ) { replyBulkdelete(out, request, reply); } else if (request.method() == "DELETE") { deleteTimer(out, request, reply); } else if ( request.method() == "POST" ) { createOrUpdateTimer(out, request, reply, false); } else if ( request.method() == "PUT" ) { createOrUpdateTimer(out, request, reply, true); } else { reply.httpReturn(501, "Only GET, DELETE, POST and PUT methods are supported."); } }
void EventsResponder::replyContentDescriptors(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler q("/events/contentdescriptors", request); if ( request.method() != "GET") { reply.httpReturn(403, "To retrieve content descriptors use the POST method!"); return; } StreamExtension se(&out); ContentDescriptorList* list; if ( q.isFormat(".json") ) { reply.addHeader("Content-Type", "application/json; charset=utf-8"); list = (ContentDescriptorList*)new JsonContentDescriptorList(&out); } else if ( q.isFormat(".html") ) { reply.addHeader("Content-Type", "text/html; charset=utf-8"); list = (ContentDescriptorList*)new HtmlContentDescriptorList(&out); } else if ( q.isFormat(".xml") ) { reply.addHeader("Content-Type", "text/xml; charset=utf-8"); list = (ContentDescriptorList*)new XmlContentDescriptorList(&out); } else { reply.httpReturn(403, "Resources are not available for the selected format. (Use: .json, .xml or .html)"); return; } list->init(); int total = 0; std::set<std::string> contentStrings; for(unsigned int i=0; i<CONTENT_DESCRIPTOR_MAX;i++) { const string contentDescr = cEvent::ContentToString(i); SerContentDescriptor cDescr; if (!contentDescr.empty() && contentStrings.find(contentDescr) == contentStrings.end()) { contentStrings.insert(contentDescr); cDescr.name = StringExtension::UTF8Decode(contentDescr); std::stringstream stream; stream << std::hex << i; std::string result( stream.str() ); switch (i) { case ecgArtsCulture: case ecgChildrenYouth: case ecgEducationalScience: case ecgLeisureHobbies: case ecgMovieDrama: case ecgMusicBalletDance: case ecgNewsCurrentAffairs: case ecgShow: case ecgSocialPoliticalEconomics: case ecgSpecial: case ecgSports: case ecgUserDefined: cDescr.isGroup = true; break; default: cDescr.isGroup = false; } cDescr.id = result; list->addDescr(cDescr); total++; } } list->setTotal(total); list->finish(); delete list; };
void EventsResponder::replyEvents(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler q("/events", request); if ( request.method() != "GET") { reply.httpReturn(403, "To retrieve information use the GET method!"); return; } EventList* eventList; if ( q.isFormat(".json") ) { reply.addHeader("Content-Type", "application/json; charset=utf-8"); eventList = (EventList*)new JsonEventList(&out); } else if ( q.isFormat(".html") ) { reply.addHeader("Content-Type", "text/html; charset=utf-8"); eventList = (EventList*)new HtmlEventList(&out); } else if ( q.isFormat(".xml") ) { reply.addHeader("Content-Type", "text/xml; charset=utf-8"); eventList = (EventList*)new XmlEventList(&out); } else { reply.httpReturn(403, "Resources are not available for the selected format. (Use: .json or .html)"); return; } string channel_id = q.getParamAsString(0); int timespan = q.getOptionAsInt("timespan");//q.getParamAsInt(1); int from = q.getOptionAsInt("from");//q.getParamAsInt(2); int start_filter = q.getOptionAsInt("start"); int limit_filter = q.getOptionAsInt("limit"); int event_id = q.getParamAsInt(1);//q.getOptionAsInt("eventid"); string onlyCount = q.getOptionAsString("only_count"); #if APIVERSNUM > 20300 LOCK_CHANNELS_READ; const cChannels& channels = *Channels; #else cChannels& channels = Channels; #endif const cChannel* channel = VdrExtension::getChannel(channel_id); if ( channel == NULL ) { /*reply.addHeader("Content-Type", "application/octet-stream"); string error_message = (string)"Could not find channel with id: " + channel_id + (string)"!"; reply.httpReturn(404, error_message); return;*/ } int channel_limit = q.getOptionAsInt("chevents"); if ( channel_limit <= -1 ) channel_limit = 0; // default channel events is 0 -> all int channel_from = q.getOptionAsInt("chfrom"); if ( channel_from <= -1 || channel != NULL ) channel_from = 0; // default channel number is 0 int channel_to = q.getOptionAsInt("chto"); if ( channel_to <= 0 || channel != NULL ) channel_to = channels.Count(); if ( from <= -1 ) from = time(NULL); // default time is now if ( timespan <= -1 ) timespan = 0; // default timespan is 0, which means all entries will be returned int to = from + timespan; #if APIVERSNUM > 20300 LOCK_SCHEDULES_READ; #else cSchedulesLock MutexLock; const cSchedules *Schedules = cSchedules::Schedules(MutexLock); #endif if( !Schedules ) { reply.httpReturn(404, "Could not find schedules!"); return; } if ( start_filter >= 0 && limit_filter >= 1 ) { eventList->activateLimit(start_filter, limit_filter); } bool initialized = false; int total = 0; for(int i=0; i<channels.Count(); i++) { const cSchedule *Schedule = Schedules->GetSchedule(channels.Get(i)->GetChannelID()); if ((channel == NULL || strcmp(channel->GetChannelID().ToString(), channels.Get(i)->GetChannelID().ToString()) == 0) && (i >= channel_from && i <= channel_to)) { if (!Schedule) { if (channel != NULL) { reply.httpReturn(404, "Could not find schedule!"); return; } } else { if (!initialized) { eventList->init(); initialized = true; } int old = 0; int channel_events = 0; for(const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event)) { int ts = event->StartTime(); int te = ts + event->Duration(); if ((ts <= to && te > from) || (te > from && timespan == 0)) { if (channel_limit == 0 || channel_limit > channel_events) { if ((event_id < 0 || event_id == (int)event->EventID()) && onlyCount != "true") { eventList->addEvent(event); channel_events++; } } } else { if (ts > to) break; if (te <= from) old++; } } total += (Schedule->Events()->Count() - old); } } } eventList->setTotal(total); eventList->finish(); delete eventList; }
void EventsResponder::replySearchResult(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler q("/events/search", request); if ( request.method() != "POST") { reply.httpReturn(403, "To search for information use the POST method!"); return; } StreamExtension se(&out); string query = q.getBodyAsString("query"); string search = q.getBodyAsString("search"); if ( query.length() == 0 && search.length() == 0 ) { reply.httpReturn(402, "Query required"); return; } EventList* eventList; if ( q.isFormat(".json") ) { reply.addHeader("Content-Type", "application/json; charset=utf-8"); eventList = (EventList*)new JsonEventList(&out); } else if ( q.isFormat(".html") ) { reply.addHeader("Content-Type", "text/html; charset=utf-8"); eventList = (EventList*)new HtmlEventList(&out); } else if ( q.isFormat(".xml") ) { reply.addHeader("Content-Type", "text/xml; charset=utf-8"); eventList = (EventList*)new XmlEventList(&out); } else { reply.httpReturn(403, "Resources are not available for the selected format. (Use: .json or .html)"); return; } eventList->init(); int start_filter = q.getOptionAsInt("start"); int limit_filter = q.getOptionAsInt("limit"); int date_filter = q.getOptionAsInt("date_limit"); if ( start_filter >= 0 && limit_filter >= 1 ) { eventList->activateLimit(start_filter, limit_filter); } if ( date_filter >= 0 ) { eventList->activateDateLimit(date_filter); } int total = 0; if ( search.length() > 0 ) { vdrlive::SearchTimer* searchtimer = new vdrlive::SearchTimer; searchtimer->SetId(0); string result = searchtimer->LoadCommonFromQuery(q); if (result.length() > 0) { reply.httpReturn(406, result.c_str()); return; } string query = searchtimer->ToText(); vdrlive::SearchResults* results = new vdrlive::SearchResults; results->GetByQuery(query); for (vdrlive::SearchResults::iterator result = results->begin(); result != results->end(); ++result) { eventList->addEvent(((cEvent*)result->GetEvent())); total++; } delete searchtimer; delete results; } else { int mode = q.getBodyAsInt("mode");// search mode (0=phrase, 1=and, 2=or, 3=exact, 4=regular expression, 5=fuzzy) string channelid = q.getBodyAsString("channelid"); //id !! bool use_title = q.getBodyAsString("use_title") == "true"; bool use_subtitle = q.getBodyAsString("use_subtitle") == "true"; bool use_description = q.getBodyAsString("use_description") == "true"; int channel = 0; const cChannel* channelInstance = VdrExtension::getChannel(channelid); if (channelInstance != NULL) { channel = channelInstance->Number(); } #if APIVERSNUM > 20300 LOCK_CHANNELS_READ; const cChannels& channels = *Channels; #else cChannels& channels = Channels; #endif if (!use_title && !use_subtitle && !use_description) use_title = true; if (mode < 0 || mode > 5) mode = 0; if (channel < 0 || channel > channels.Count()) channel = 0; if (query.length() > 100) query = query.substr(0,100); //don't allow more than 100 characters, NOTE: maybe I should add a limitation to the Responderclass? struct Epgsearch_searchresults_v1_0* epgquery = new struct Epgsearch_searchresults_v1_0; epgquery->query = (char*)query.c_str(); epgquery->mode = mode; epgquery->channelNr = channel; epgquery->useTitle = use_title; epgquery->useSubTitle = use_subtitle; epgquery->useDescription = use_description; cPlugin *Plugin = cPluginManager::GetPlugin("epgsearch"); if (Plugin) { if (Plugin->Service("Epgsearch-searchresults-v1.0", NULL)) { if (Plugin->Service("Epgsearch-searchresults-v1.0", epgquery)) { cList< Epgsearch_searchresults_v1_0::cServiceSearchResult>* result = epgquery->pResultList; Epgsearch_searchresults_v1_0::cServiceSearchResult* item = NULL; if (result != NULL) { for(int i=0;i<result->Count();i++) { item = result->Get(i); eventList->addEvent(((cEvent*)item->event)); total++; } } } else { reply.httpReturn(406, "Internal (epgsearch) error, check parameters."); } } else { reply.httpReturn(405, "Plugin-service not available."); } } else { reply.httpReturn(404, "Plugin not installed!"); } delete epgquery; } eventList->setTotal(total); eventList->finish(); delete eventList; }
void RecordingsResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler::addHeader(reply); bool found = false; if ( request.method() == "OPTIONS" ) { reply.addHeader("Allow", "GET, POST, DELETE"); reply.httpReturn(200, "OK"); return; } if ((int)request.url().find("/recordings/play") == 0 ) { if (request.method() == "POST") { playRecording(out, request, reply); reply.addHeader("Content-Type", "text/plain; charset=utf-8"); } else { reply.httpReturn(501, "Only POST method is supported by the /recordings/play service."); } found = true; } else if ((int)request.url().find("/recordings/rewind") == 0 ) { if (request.method() == "POST") { rewindRecording(out, request, reply); reply.addHeader("Content-Type", "text/plain; charset=utf-8"); } else { reply.httpReturn(501, "Only POST method is supported by the /recordings/rewind service."); } found = true; } else if ((int)request.url().find("/recordings/cut") == 0 ) { if (request.method() == "GET") { showCutterStatus(out, request, reply); } else if (request.method() == "POST") { cutRecording(out, request, reply); } else { reply.httpReturn(501, "Only GET and POST methods are supported by the /recordings/cut service."); } found = true; } else if ((int)request.url().find("/recordings/editedfile") == 0 ) { if (request.method() == "GET") { replyEditedFileName(out, request, reply); } else { reply.httpReturn(501, "Only GET method are supported by the /recordings/lastedited service."); } found = true; } else if ((int)request.url().find("/recordings/marks") == 0 ) { if (request.method() == "DELETE") { deleteMarks(out, request, reply); } else if (request.method() == "POST") { saveMarks(out, request, reply); } else { reply.httpReturn(501, "Only DELETE and POST methods are supported by the /recordings/marks service."); } found = true; } else if ((int)request.url().find("/recordings/move") == 0 ) { if (request.method() == "POST") { moveRecording(out, request, reply); } else { reply.httpReturn(501, "Only POST method is supported by the /recordings/move service."); } found = true; } else if ((int) request.url().find("/recordings/updates") == 0 ) { if (request.method() == "GET") { replyUpdates(out, request, reply); } else { reply.httpReturn(501, "Only GET method is supported by the /recordings/updates service."); } found = true; } else if ((int) request.url().find("/recordings/sync") == 0 ) { if (request.method() == "POST") { replySyncList(out, request, reply); } else { reply.httpReturn(501, "Only POST method is supported by the /recordings/sync service."); } found = true; } else if ((int) request.url().find("/recordings/delete") == 0 ) { if (request.method() == "POST") { deleteRecordingByName(out, request, reply); } else if (request.method() == "DELETE") { deleteRecordingByName(out, request, reply); } else { reply.httpReturn(501, "Only POST and DELETE methods are supported by the /recordings/delete service."); } found = true; } // original /recordings service else if ((int) request.url().find("/recordings") == 0 ) { if (request.method() == "GET") { showRecordings(out, request, reply); } else if (request.method() == "DELETE") { deleteRecording(out, request, reply); } else { reply.httpReturn(501, "Only GET, POST and DELETE methods are supported by the /recordings service."); } found = true; } if (!found) { reply.httpReturn(403, "Service not found"); } }