diff --git a/epgsearch/services.h b/epgsearch/services.h index 35cca9b..85f81a4 100644 --- a/epgsearch/services.h +++ b/epgsearch/services.h @@ -157,7 +157,7 @@ class cServiceHandler struct Epgsearch_services_v1_0 { // in/out - std::auto_ptr handler; + std::unique_ptr handler; }; // Data structures for service "Epgsearch-services-v1.1" @@ -173,7 +173,7 @@ class cServiceHandler_v1_1 : public cServiceHandler struct Epgsearch_services_v1_1 { // in/out - std::auto_ptr handler; + std::unique_ptr handler; }; // Data structures for service "Epgsearch-services-v1.2" @@ -189,7 +189,7 @@ class cServiceHandler_v1_2 : public cServiceHandler_v1_1 struct Epgsearch_services_v1_2 { // in/out - std::auto_ptr handler; + std::unique_ptr handler; }; #endif diff --git a/events.cpp b/events.cpp index 17117a6..437ea3a 100644 --- a/events.cpp +++ b/events.cpp @@ -28,7 +28,7 @@ void EventsResponder::reply(ostream& out, cxxtools::http::Request& request, cxxt void EventsResponder::replyEvents(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { - QueryHandler q("/events", request); + QueryHandler q("/events", request); if ( request.method() != "GET") { @@ -38,7 +38,7 @@ void EventsResponder::replyEvents(ostream& out, cxxtools::http::Request& request EventList* eventList; - + if ( q.isFormat(".json") ) { reply.addHeader("Content-Type", "application/json; charset=utf-8"); eventList = (EventList*)new JsonEventList(&out); @@ -65,6 +65,8 @@ void EventsResponder::replyEvents(ostream& out, cxxtools::http::Request& request string onlyCount = q.getOptionAsString("only_count"); #if APIVERSNUM > 20300 + /* create a dummer timer lock to avoid deadlock*/ + LOCK_TIMERS_READ; LOCK_CHANNELS_READ; const cChannels& channels = *Channels; #else @@ -113,7 +115,31 @@ void EventsResponder::replyEvents(ostream& out, cxxtools::http::Request& request int total = 0; for(int i=0; iGetSchedule(channels.Get(i)->GetChannelID()); - + +#if APIVERSNUM > 20300 + if (Channels->Get(i)->GroupSep()) { // we have a group-separator + if (channel_from > 0) channel_from += 1; + if (channel_to > 0 && channel_to < Channels->Count()) channel_to += 1; + continue; + } + + if (!Schedule) { + channel_from += 1; + if (channel_to < Channels->Count()) channel_to += 1; + } +#else + if (Channels.Get(i)->GroupSep()) { // we have a group-separator + if (channel_from > 0) channel_from += 1; + if (channel_to > 0 && channel_to < Channels.Count()) channel_to += 1; + continue; + } + + if (!Schedule) { + channel_from += 1; + if (channel_to < Channels.Count()) channel_to += 1; + } +#endif + if ((channel == NULL || strcmp(channel->GetChannelID().ToString(), channels.Get(i)->GetChannelID().ToString()) == 0) && (i >= channel_from && i <= channel_to)) { if (!Schedule) { if (channel != NULL) { diff --git a/recordings.cpp b/recordings.cpp index ce7553a..10b34e4 100644 --- a/recordings.cpp +++ b/recordings.cpp @@ -15,14 +15,21 @@ void RecordingsResponder::reply(ostream& out, cxxtools::http::Request& request, if ((int)request.url().find("/recordings/play") == 0 ) { - if ( request.method() == "GET" ) { + if (request.method() == "POST") { playRecording(out, request, reply); reply.addHeader("Content-Type", "text/plain; charset=utf-8"); - } else if (request.method() == "POST") { + } 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 GET and POST method is supported by the /recordings/play service."); + reply.httpReturn(501, "Only POST method is supported by the /recordings/rewind service."); } found = true; } @@ -84,6 +91,17 @@ void RecordingsResponder::reply(ostream& out, cxxtools::http::Request& request, } 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 ) { @@ -194,8 +212,10 @@ RecordingList* RecordingsResponder::getRecordingList(ostream& out, QueryHandler } else { + // we can prevent a lot of trouble, if we add a default header and a recordingList reply.httpReturn(502, "Resources are not available for the selected format. (Use: .json, .xml or .html)"); return NULL; + } return recordingList; @@ -204,29 +224,65 @@ RecordingList* RecordingsResponder::getRecordingList(ostream& out, QueryHandler void RecordingsResponder::playRecording(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler q("/recordings/play", request); - const cRecording* recording = getRecordingByRequest(q); - if ( recording != NULL ) { - TaskScheduler::get()->SwitchableRecording(recording); +#if APIVERSNUM > 20300 + LOCK_RECORDINGS_READ; + const cRecordings& recordings = *Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings& recordings = Recordings; +#endif + const cRecording* recording = NULL; + + string recording_file = q.getBodyAsString("file"); + if (recording_file.length() > 0) + recording = recordings.GetByName(recording_file.c_str()); + else { + int recording_number = q.getParamAsInt(0); + if (recording_number < 0 || recording_number >= recordings.Count()) + reply.httpReturn(404, "Wrong recording number!"); + else + recording = recordings.Get(recording_number); + } + + if (recording != NULL) { + TaskScheduler::get()->SwitchableRecording(recording); } else { - reply.httpReturn(404, "Wrong recording number or filename!"); + reply.httpReturn(404, "Wrong recording name or number!"); } } void RecordingsResponder::rewindRecording(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { - QueryHandler q("/recordings/play", request); - const cRecording* recording = getRecordingByRequest(q); - - if ( recording != NULL ) { - cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording - cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); - ResumeFile.Delete(); - TaskScheduler::get()->SwitchableRecording(recording); + QueryHandler q("/recordings/rewind", request); +#if APIVERSNUM > 20300 + LOCK_RECORDINGS_READ; + const cRecordings& recordings = *Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings& recordings = Recordings; +#endif + const cRecording* recording = NULL; + + string recording_file = q.getBodyAsString("file"); + if (recording_file.length() > 0) + recording = recordings.GetByName(recording_file.c_str()); + else { + int recording_number = q.getParamAsInt(0); + if (recording_number < 0 || recording_number >= recordings.Count()) + reply.httpReturn(404, "Wrong recording number!"); + else + recording = recordings.Get(recording_number); + } + + if (recording != NULL) { + TaskScheduler::get()->SetRewind(true); + TaskScheduler::get()->SwitchableRecording(recording); } else { - reply.httpReturn(404, "Wrong recording number!"); + reply.httpReturn(404, "Wrong recording name or number!"); } } + /* move or copy recording */ void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { @@ -237,8 +293,8 @@ void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& r #if APIVERSNUM > 20300 - LOCK_RECORDINGS_READ; - const cRecordings& recordings = *Recordings; + LOCK_RECORDINGS_WRITE; + cRecordings& recordings = *Recordings; #else cThreadLock RecordingsLock(&Recordings); cRecordings& recordings = Recordings; @@ -258,13 +314,32 @@ void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& r return; } - string newname = VdrExtension::MoveRecording(recording, VdrExtension::FileSystemExchangeChars(target.c_str(), true), copy_only); - - if (newname.length() <= 0) { + //string newname = VdrExtension::MoveRecording(recording, VdrExtension::FileSystemExchangeChars(target.c_str(), true), copy_only); + + string oldname = recording->FileName(); + size_t found = oldname.find_last_of("/"); + + if (found == string::npos) { LOG_ERROR_STR(source.c_str()); reply.httpReturn(503, "File copy failed!"); return; } + +#if APIVERSNUM > 20101 + string newname = string(cVideoDirectory::Name()) + "/" + VdrExtension::FileSystemExchangeChars(target.c_str(), true) + oldname.substr(found); +#else + string newname = string(VideoDirectory) + "/" + VdrExtension::FileSystemExchangeChars(target.c_str(), true) + oldname.substr(found); +#endif + if (!VdrExtension::MoveDirectory(oldname.c_str(), newname.c_str(), copy_only)) { + esyslog("[Restfulapi]: renaming failed from '%s' to '%s'", oldname.c_str(), newname.c_str()); + reply.httpReturn(503, "File copy failed!"); + return; + } + + if (!copy_only) + recordings.DelByName(oldname.c_str()); + recordings.AddByName(newname.c_str()); + cRecordingUserCommand::InvokeCommand(*cString::sprintf("rename \"%s\"", *strescape(oldname.c_str(), "\\\"$'")), newname.c_str()); const cRecording* new_recording = recordings.GetByName(newname.c_str()); if (!new_recording) { @@ -277,6 +352,9 @@ void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& r esyslog("restfulapi: %s, %d", new_recording->FileName(), new_recording->Index()); RecordingList* recordingList = getRecordingList(out, q, reply); + if (recordingList == NULL) { + return; + } recordingList->addRecording(new_recording, new_recording->Index(), NULL, ""); recordingList->setTotal(recordings.Count()); recordingList->finish(); @@ -285,42 +363,77 @@ void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& r void RecordingsResponder::replyEditedFileName(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { - QueryHandler q("/recordings/editedfile", request); - const cRecording* recording = getRecordingByRequest(q); - RecordingList* recordingList = getRecordingList(out, q, reply); - const cRecording* editedFile = NULL; - - if ( recordingList == NULL ) { - - return; - }; - if ( recording == NULL ) { - + QueryHandler q("/recordings/editedfile", request); + + const cRecording* recording = getRecordingByRequest(q); + if (recording == NULL) { reply.httpReturn(404, "Requested recording not found!"); return; - } + } + + RecordingList* recordingList = getRecordingList(out, q, reply); + if (recordingList == NULL) { + return; + } #if APIVERSNUM > 20300 - LOCK_RECORDINGS_READ; - const cRecordings& recordings = *Recordings; + LOCK_RECORDINGS_READ; + const cRecordings& recordings = *Recordings; #else - cRecordings& recordings = Recordings; + cRecordings& recordings = Recordings; #endif - editedFile = recordings.GetByName(cCutter::EditedFileName(recording->FileName())); - if ( editedFile == NULL ) { - + + const cRecording* editedFile = recordings.GetByName(cCutter::EditedFileName(recording->FileName())); + if (editedFile == NULL) { reply.httpReturn(404, "Requested edited file not found!"); return; - }; - - recordingList->init(); - recordingList->addRecording(editedFile, editedFile->Index(), NULL, ""); - recordingList->setTotal(recordings.Count()); - recordingList->finish(); - delete recordingList; + } + recordingList->init(); + recordingList->addRecording(editedFile, editedFile->Index(), NULL, ""); + recordingList->setTotal(recordings.Count()); + recordingList->finish(); + delete recordingList; }; +/* delete recording by file name */ +void RecordingsResponder::deleteRecordingByName(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) +{ + QueryHandler q("/recordings/delete", request); + string recording_file = q.getBodyAsString("file"); + if (recording_file.length() > 0) { +#if APIVERSNUM > 20300 + LOCK_RECORDINGS_WRITE; + cRecordings& recordings = *Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings& recordings = Recordings; +#endif + cRecording* delRecording = recordings.GetByName(recording_file.c_str()); + + string syncId = q.getOptionAsString("syncId"); + + if ( delRecording == NULL ) { + reply.httpReturn(404, "Recording not found!"); + return; + } + + esyslog("restfulapi: delete recording %s", delRecording->FileName()); + if ( delRecording->Delete() ) { + + if (syncId != "") { + SyncMap* syncMap = new SyncMap(q, true); + syncMap->erase(StringExtension::toString(delRecording->FileName())); + } + + recordings.DelByName(delRecording->FileName()); + reply.httpReturn(200, "Recording deleted!"); + return; + } + } + reply.httpReturn(500, "Recording could not be deleted!"); +} + void RecordingsResponder::deleteRecording(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) { QueryHandler q("/recordings", request); @@ -358,9 +471,13 @@ void RecordingsResponder::showRecordings(ostream& out, cxxtools::http::Request& QueryHandler q("/recordings", request); bool read_marks = q.getOptionAsString("marks") == "true"; string sync_id = q.getOptionAsString("syncId"); - SyncMap* sync_map = new SyncMap(q); RecordingList* recordingList = getRecordingList(out, q, reply, read_marks); + if (recordingList == NULL) { + return; + } + + SyncMap* sync_map = new SyncMap(q); int start_filter = q.getOptionAsInt("start"); int limit_filter = q.getOptionAsInt("limit"); @@ -535,6 +652,9 @@ void RecordingsResponder::initServerList(ostream& out, cxxtools::http::Request& QueryHandler q("/recordings/sync", request); RecordingList* recordingList = getRecordingList(out, q, reply, false); + if (recordingList == NULL) { + return; + } #if APIVERSNUM > 20300 LOCK_RECORDINGS_READ; @@ -552,6 +672,9 @@ void RecordingsResponder::sendSyncList(ostream& out, cxxtools::http::Request& re QueryHandler q("/recordings/sync", request); RecordingList* updates = getRecordingList(out, q, reply, false); + if (updates == NULL) { + return; + } map updatesList; map::iterator itUpdates; diff --git a/recordings.h b/recordings.h index ae7e500..b015531 100644 --- a/recordings.h +++ b/recordings.h @@ -68,6 +68,7 @@ class RecordingsResponder : public cxxtools::http::Responder virtual void reply(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply); void deleteRecording(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply); + void deleteRecordingByName(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply); void showRecordings(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply); void saveMarks(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply); void deleteMarks(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply); diff --git a/restfulapi.cpp b/restfulapi.cpp index a207518..1546d49 100644 --- a/restfulapi.cpp +++ b/restfulapi.cpp @@ -196,6 +196,12 @@ void cPluginRestfulapi::MainThreadHook(void) const cRecording* recording = scheduler->SwitchableRecording(); if (recording != NULL) { + if (scheduler->IsRewind()) { + cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording + cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); + ResumeFile.Delete(); + scheduler->SetRewind(false); + } cReplayControl::SetRecording(recording->FileName()); scheduler->SwitchableRecording(NULL); cControl::Shutdown(); diff --git a/timers.cpp b/timers.cpp index 1acc430..07ba229 100644 --- a/timers.cpp +++ b/timers.cpp @@ -30,12 +30,7 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& { QueryHandler q("/timers", request); - - -#if APIVERSNUM > 20300 - LOCK_TIMERS_WRITE; - cTimers& timers = *Timers; -#else +#if APIVERSNUM < 20300 cTimers& timers = Timers; if ( timers.BeingEdited() ) { @@ -59,11 +54,13 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& string day = v.ConvertDay(q.getBodyAsString("day")); const cChannel* chan = v.ConvertChannel(q.getBodyAsString("channel")); cTimer* timer_orig = v.ConvertTimer(q.getBodyAsString("timer_id")); - - if ( update == false ) { //create - int eventid = q.getBodyAsInt("eventid"); - int minpre = q.getBodyAsInt("minpre"); - int minpost = q.getBodyAsInt("minpost"); + const cTimer* timerOrigRead = VdrExtension::getTimer(q.getBodyAsString("timer_id")); + int eventid = q.getBodyAsInt("eventid"); + int minpre = q.getBodyAsInt("minpre"); + int minpost = q.getBodyAsInt("minpost"); + if (minpre < 0) minpre = 0; + if (minpost < 0) minpost = 0; + if ( update == false ) { //create timer by event ID if (eventid >= 0 && chan != NULL) { const cEvent* event = VdrExtension::GetEventById((tEventID)eventid, chan); @@ -71,8 +68,6 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& reply.httpReturn(407, "eventid invalid"); return; } else { - if (minpre < 0) minpre = 0; - if (minpost < 0) minpost = 0; if (!v.IsFlagsValid(flags)) flags = 1; if (!v.IsFileValid(file)) file = (string)event->Title(); if (!v.IsWeekdaysValid(weekdays)) weekdays = "-------"; @@ -89,7 +84,7 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& << StringExtension::addZeros((starttime->tm_mon + 1), 2) << "-" << StringExtension::addZeros((starttime->tm_mday), 2); day = daystream.str(); - + start = starttime->tm_hour * 100 + starttime->tm_min; struct tm *stoptime = localtime(&estop); @@ -108,8 +103,34 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& if ( chan == NULL ) { error = true; error_values += "channel, "; } } } else { //update - if ( timer_orig == NULL ) { error = true; error_values += "timer_id, "; } - if ( !error ) { + if ( (timer_orig == NULL) || (timerOrigRead == NULL) ) { error = true; error_values += "timer_id, "; } + if ( !error ) + { + if (!v.IsStopValid(stop) || !v.IsStartValid(start)) /* update timer based on premin and postmin */ + { + tEventID eventid_; + eventid_ = timerOrigRead->Event()->EventID(); + chan = timerOrigRead->Channel(); + const cEvent* event = VdrExtension::GetEventById((tEventID)eventid_, chan); + if (event == NULL) { + reply.httpReturn(407, "eventid invalid"); + return; + } + time_t estart = event->StartTime() - minpre * 60; + time_t estop = event->EndTime() + minpost * 60; + struct tm *starttime = localtime(&estart); + + ostringstream daystream; + daystream << StringExtension::addZeros((starttime->tm_year + 1900), 4) << "-" + << StringExtension::addZeros((starttime->tm_mon + 1), 2) << "-" + << StringExtension::addZeros((starttime->tm_mday), 2); + day = daystream.str(); + + start = starttime->tm_hour * 100 + starttime->tm_min; + + struct tm *stoptime = localtime(&estop); + stop = stoptime->tm_hour * 100 + stoptime->tm_min; + } if ( !v.IsFlagsValid(flags) ) { flags = timer_orig->Flags(); } if ( !v.IsFileValid(file) ) { file = v.ConvertFile((string)timer_orig->File()); } if ( !v.IsLifetimeValid(lifetime) ) { lifetime = timer_orig->Lifetime(); } @@ -118,9 +139,15 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& if ( !v.IsStartValid(start) ) { start = timer_orig->Start(); } if ( !v.IsWeekdaysValid(weekdays) ) { weekdays = v.ConvertWeekdays(timer_orig->WeekDays()); } if ( !v.IsDayValid(day) ) { day = v.ConvertDay(timer_orig->Day()); } - if ( chan == NULL ) { chan = (cChannel*)timer_orig->Channel(); } - if ( aux == "" ) { aux = v.ConvertAux(timer_orig->Aux()); } - } + if ( chan == NULL ) { chan = (cChannel*)timer_orig->Channel();} + if (aux == "") + { + if (timer_orig->Aux() != NULL) + { + aux = v.ConvertAux(timer_orig->Aux()); + } + } + } } if (error) { @@ -141,12 +168,18 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& << file << ":" << aux; - dsyslog("restfulapi: /%s/ ", builder.str().c_str()); + dsyslog("restfulapi timer info: /%s/ ", builder.str().c_str()); chan = NULL; if ( update == false ) { // create timer cTimer* timer = new cTimer(); - if ( timer->Parse(builder.str().c_str()) ) { + if ( timer->Parse(builder.str().c_str()) ) { +#if APIVERSNUM > 20300 + LOCK_TIMERS_WRITE; + Timers->SetExplicitModify(); + cTimer* checkTimer = Timers->GetTimer(timer); +#else cTimer* checkTimer = timers.GetTimer(timer); +#endif if ( checkTimer != NULL ) { delete timer; reply.httpReturn(403, "Timer already defined!"); @@ -154,14 +187,13 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& } else { replyCreatedId(timer, request, reply, out); #if APIVERSNUM > 20300 - LOCK_SCHEDULES_READ; timer->SetEventFromSchedule(Schedules); + Timers->Add(timer); + Timers->SetModified(); #else timer->SetEventFromSchedule(); -#endif timers.Add(timer); -#if APIVERSNUM <= 20300 timers.SetModified(); #endif esyslog("restfulapi: timer created!"); @@ -173,12 +205,12 @@ void TimersResponder::createOrUpdateTimer(ostream& out, cxxtools::http::Request& } else { if ( timer_orig->Parse(builder.str().c_str()) ) { #if APIVERSNUM > 20300 - - LOCK_SCHEDULES_READ; - timer_orig->SetEventFromSchedule(Schedules); + LOCK_SCHEDULES_READ; + timer_orig->SetEventFromSchedule(Schedules); + //Timers->SetModified(); #else - timer_orig->SetEventFromSchedule(); - timers.SetModified(); + timer_orig->SetEventFromSchedule(); + timers.SetModified(); #endif replyCreatedId(timer_orig, request, reply, out); esyslog("restfulapi: updating timer successful!"); @@ -216,10 +248,7 @@ void TimersResponder::deleteTimer(ostream& out, cxxtools::http::Request& request { QueryHandler q("/timers", request); -#if APIVERSNUM > 20300 - LOCK_TIMERS_WRITE; - cTimers& timers = *Timers; -#else +#if APIVERSNUM < 20300 cTimers& timers = Timers; if ( timers.BeingEdited() ) { @@ -235,16 +264,24 @@ void TimersResponder::deleteTimer(ostream& out, cxxtools::http::Request& request if ( timer == NULL) { reply.httpReturn(404, "Timer id invalid!"); } else { +#if APIVERSNUM > 20300 + LOCK_TIMERS_WRITE; + Timers->SetExplicitModify(); +#endif if ( timer->Recording() ) { timer->Skip(); #if APIVERSNUM > 20300 cRecordControls::Process(Timers, time(NULL)); + } + Timers->Del(timer); + Timers->SetModified(); #else cRecordControls::Process(time(NULL)); -#endif } timers.Del(timer); timers.SetModified(); +#endif + reply.httpReturn(200, "Timer deleted."); } } @@ -253,10 +290,7 @@ void TimersResponder::replyBulkdelete(std::ostream& out, cxxtools::http::Request QueryHandler q("/timers/bulkdelete", request); -#if APIVERSNUM > 20300 - LOCK_TIMERS_WRITE; - cTimers& timers = *Timers; -#else +#if APIVERSNUM < 20300 cTimers& timers = Timers; if ( timers.BeingEdited() ) { @@ -298,16 +332,23 @@ void TimersResponder::replyBulkdelete(std::ostream& out, cxxtools::http::Request if ( timer == NULL ) { result.deleted = false; } else { +#if APIVERSNUM > 20300 + LOCK_TIMERS_WRITE; + Timers->SetExplicitModify(); +#endif if ( timer->Recording() ) { - timer->Skip(); + timer->Skip(); #if APIVERSNUM > 20300 cRecordControls::Process(Timers, time(NULL)); + } + Timers->Del(timer); + Timers->SetModified(); #else cRecordControls::Process(time(NULL)); -#endif } timers.Del(timer); timers.SetModified(); +#endif result.deleted = true; } list->addDeleted(result); diff --git a/tools.cpp b/tools.cpp index 67aa578..b80209f 100644 --- a/tools.cpp +++ b/tools.cpp @@ -830,7 +830,7 @@ bool VdrExtension::IsRecording(const cRecording* recording) const cTimer* VdrExtension::TimerExists(const cEvent* event) { -#if APIVERSNUM > 20300 +#if APIVERSNUM > 20300 LOCK_TIMERS_READ; const cTimers& timers = *Timers; #else @@ -859,7 +859,7 @@ const cTimer* VdrExtension::TimerExists(const cEvent* event) } } } - return NULL; + return NULL; } vector< const cTimer* > VdrExtension::SortedTimers() diff --git a/tools.h b/tools.h index bb5438a..1e056c9 100644 --- a/tools.h +++ b/tools.h @@ -198,7 +198,6 @@ class FileExtension { class VdrExtension { private: - static bool MoveDirectory(std::string const & sourceDir, std::string const & targetDir, bool copy = false); public: static const cChannel* getChannel(int number); static const cChannel* getChannel(std::string id); @@ -219,6 +218,7 @@ class VdrExtension static std::string getVideoDiskSpace(); static std::string FileSystemExchangeChars(std::string const & s, bool ToFileSystem); static std::string MoveRecording(cRecording const * recording, std::string const & name, bool copy = false); + static bool MoveDirectory(std::string const & sourceDir, std::string const & targetDir, bool copy = false); static cDvbDevice* getDevice(int index); }; @@ -380,6 +380,7 @@ class TaskScheduler tChannelID _channel; const cRecording* _recording; cMutex _channelMutex; + bool _bRewind; public: TaskScheduler() { _channel = tChannelID::InvalidID; _recording = NULL; }; ~TaskScheduler(); @@ -390,6 +391,8 @@ class TaskScheduler tChannelID SwitchableChannel(); void SwitchableRecording(const cRecording* recording) { _recording = recording; } const cRecording* SwitchableRecording() { return _recording; } + void SetRewind(bool bRewind) { _bRewind = bRewind; } + bool IsRewind() { return _bRewind; } }; #endif