void RecordingsResponder::replyEditedFileName(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply) {

   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;
#else
   cRecordings& recordings = Recordings;
#endif
    
   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;
};
void RecordingsResponder::showRecordings(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
{
  QueryHandler q("/recordings", request);
  bool read_marks = q.getOptionAsString("marks") == "true";
  string sync_id = q.getOptionAsString("syncId");

  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");
  
  const cRecording* recording = getRecordingByRequest(q);

  if ( start_filter >= 0 && limit_filter >= 1 ) {
     recordingList->activateLimit(start_filter, limit_filter);
  }

  recordingList->init();

#if APIVERSNUM > 20300
    LOCK_RECORDINGS_READ;
    const cRecordings& recordings = *Recordings;
#else
    cRecordings& recordings = Recordings;
#endif

  if ( recording == NULL ) {
     for (int i = 0; i < recordings.Count(); i++) {
        recordingList->addRecording(recordings.Get(i), i, sync_map, "");
     }
  } else {
     recordingList->addRecording(recording, recording->Index(), sync_map, "");
  }
  recordingList->setTotal(recordings.Count());

  recordingList->finish();
  delete recordingList;

  if (sync_map->active()) {
      sync_map->write();
  }
  delete sync_map;
}
void RecordingsResponder::showRecordings(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
{
  QueryHandler q("/recordings", request);
  RecordingList* recordingList;
  bool read_marks = q.getOptionAsString("marks") == "true";

  if ( q.isFormat(".json") ) {
     reply.addHeader("Content-Type", "application/json; charset=utf-8");
     recordingList = (RecordingList*)new JsonRecordingList(&out, read_marks);
  } else if ( q.isFormat(".html") ) {
     reply.addHeader("Content-Type", "text/html; charset=utf-8");
     recordingList = (RecordingList*)new HtmlRecordingList(&out, read_marks);
  } else if ( q.isFormat(".xml") )  {
     reply.addHeader("Content-Type", "text/xml; charset=utf-8");
     recordingList = (RecordingList*)new XmlRecordingList(&out, read_marks);
  } else {
     reply.httpReturn(404, "Resources are not available for the selected format. (Use: .json or .html)");
     return;
  }

  int start_filter = q.getOptionAsInt("start");
  int limit_filter = q.getOptionAsInt("limit");
  
  int requested_item = q.getParamAsInt(0);

  if ( start_filter >= 0 && limit_filter >= 1 ) {
     recordingList->activateLimit(start_filter, limit_filter);
  }

  recordingList->init();
  
  cRecording* recording = NULL;
  for (int i = 0; i < Recordings.Count();i++) {
     if ( requested_item == i || requested_item < 0 ) {
        recording = Recordings.Get(i);
        recordingList->addRecording(recording, i); 
     }
  }
  recordingList->setTotal(Recordings.Count());

  recordingList->finish();
  delete recordingList;
}
void RecordingsResponder::sendSyncList(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply, SyncMap* sync_map) {

	QueryHandler q("/recordings/sync", request);
	RecordingList* updates = getRecordingList(out, q, reply, false);
	if (updates == NULL) {
	   return;
	}
	map<string, string> updatesList;
	map<string, string>::iterator itUpdates;

	updatesList = sync_map->getUpdates();
	updates->init();

	esyslog("restfulapi: recording updates: %d", (int)updatesList.size());

#if APIVERSNUM > 20300
    LOCK_RECORDINGS_READ;
    const cRecordings& recordings = *Recordings;
#else
    cRecordings& recordings = Recordings;
#endif

	for (itUpdates = updatesList.begin(); itUpdates != updatesList.end(); itUpdates++) {

		if ( "delete" != itUpdates->second) {
			const cRecording* recording = recordings.GetByName(itUpdates->first.c_str());
			updates->addRecording(recording, recording->Index(), NULL, itUpdates->second, true);
		} else {
			const cRecording* recording = new cRecording(itUpdates->first.c_str());
			updates->addRecording(recording, -1, NULL, itUpdates->second, true);
			delete recording;
		}
	}
	updates->setTotal(updatesList.size());
	updates->finish();
	delete updates;
};
/* move or copy recording */
void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
{
   QueryHandler q("/recordings/move", request);
   string source = q.getBodyAsString("source");
   string target = q.getBodyAsString("target");
   bool copy_only = q.getBodyAsBool("copy_only");


#if APIVERSNUM > 20300
    LOCK_RECORDINGS_WRITE;
    cRecordings& recordings = *Recordings;
#else
    cThreadLock RecordingsLock(&Recordings);
    cRecordings& recordings = Recordings;
#endif

   if (source.length() <= 0 || target.length() <= 0) {
      reply.httpReturn(404, "Missing file name!");
      return;
   } else if (access(source.c_str(), F_OK) != 0) {
      reply.httpReturn(504, "Path is invalid!");
      return;
   }

   const cRecording* recording = recordings.GetByName(source.c_str());
   if (!recording) {
      reply.httpReturn(504, "Recording not found!");
      return;
   }

   //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) {
      LOG_ERROR_STR(newname.c_str());
      reply.httpReturn(504, "Recording not found, after moving!");
      return;
   }


   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();
   delete recordingList;
}