5 #include <jsoncpp/json/json.h>
8 #include <vdr/videodir.h>
9 #include <vdr/recording.h>
11 #include <vdr/timers.h>
15 int jsonserver_request_handler(struct mg_connection *conn)
17 Log* log = Log::getInstance();
18 const struct mg_request_info *request_info = mg_get_request_info(conn);
20 if (strcmp(request_info->uri, "/jsonserver")) return 0; // not for us
23 int wvrl = mg_get_var(request_info->query_string, strlen(request_info->query_string), "req", wvrequest, 20);
26 log->log("JSONServer", Log::ERR, "Could not decode req");
31 if (!strcmp(request_info->request_method, "OPTIONS"))
33 mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
34 mg_printf(conn, "%s", "Access-Control-Allow-Origin: *\r\n");
35 mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
43 if (!strcmp(request_info->request_method, "POST"))
45 const char* contentLength = mg_get_header(conn, "Content-Length");
46 int contentLengthI = atoi(contentLength);
47 log->log("JSONServer", Log::DEBUG, "POST data content length: %i", contentLengthI);
48 if (contentLengthI > 10000)
50 log->log("JSONServer", Log::DEBUG, "Length > 10000, rejecting");
54 if (contentLengthI > 0)
56 // FIXME - assume for now that all post data will be small enough to have arrived immediately
57 int bytesRead = mg_read(conn, postData, contentLengthI);
58 if (bytesRead != contentLengthI)
60 log->log("JSONServer", Log::DEBUG, "Could not read up to contentLength");
63 postData[contentLengthI] = '\0';
70 if (!strcmp(wvrequest, "reclist")) success = jsonserver_reclist(js);
71 else if (!strcmp(wvrequest, "recinfo")) success = jsonserver_recinfo(js, postData);
72 else if (!strcmp(wvrequest, "recdel")) success = jsonserver_recdel(js, postData);
73 else if (!strcmp(wvrequest, "recmove")) success = jsonserver_recmove(js, postData);
74 else if (!strcmp(wvrequest, "recstop")) success = jsonserver_recstop(js, postData);
75 else if (!strcmp(wvrequest, "channellist")) success = jsonserver_channellist(js);
76 else if (!strcmp(wvrequest, "channelschedule")) success = jsonserver_channelschedule(js, postData);
77 else if (!strcmp(wvrequest, "timerlist")) success = jsonserver_timerlist(js);
78 else if (!strcmp(wvrequest, "timerdel")) success = jsonserver_timerdel(js, postData);
79 else if (!strcmp(wvrequest, "timerset")) success = jsonserver_timerset(js, postData);
81 if (!success) return 0; // the specific handler failed badly
83 // Now js will be filled
85 Json::StyledWriter sw;
86 std::string jsonout = sw.write(js);
87 mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
88 mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
89 mg_write(conn, jsonout.c_str(), jsonout.length());
94 else if (event == MG_EVENT_LOG)
96 if (request_info->status_code == 400) // bad request
98 log->log("Mongoose", Log::DEBUG, "400 BAD REQUEST:");
99 log->log("Mongoose", Log::DEBUG, request_info->request_method);
100 log->log("Mongoose", Log::DEBUG, request_info->uri);
101 log->log("Mongoose", Log::DEBUG, request_info->http_version);
102 log->log("Mongoose", Log::DEBUG, request_info->query_string);
103 log->log("Mongoose", Log::DEBUG, request_info->log_message);
104 for (int i = 0; i < request_info->num_headers; i++)
106 log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
111 log->log("Mongoose", Log::DEBUG, request_info->log_message);
112 log->log("Mongoose", Log::DEBUG, request_info->uri);
117 // other events not handled:
118 // MG_HTTP_ERROR, MG_INIT_SSL
119 // Let mongoose do something with those
127 bool jsonserver_reclist(Json::Value& js)
129 Log* log = Log::getInstance();
130 log->log("JSONServer", Log::DEBUG, "reclist");
133 int Percent = VideoDiskSpace(&FreeMB);
134 int Total = (FreeMB / (100 - Percent)) * 100;
136 js["MBFree"] = FreeMB;
137 js["Percent"] = Percent;
140 Json::Value jsrecordings;
141 cRecordings Recordings;
143 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
146 oneRec["StartTime"] = (Json::UInt)recording->Start();
147 oneRec["Length"] = (Json::UInt)recording->LengthInSeconds();
148 oneRec["IsNew"] = recording->IsNew();
149 oneRec["Name"] = recording->Name();
150 oneRec["Filename"] = recording->FileName();
151 oneRec["FileSizeMB"] = recording->FileSizeMB();
152 jsrecordings.append(oneRec);
154 js["Recordings"] = jsrecordings;
159 bool jsonserver_recinfo(Json::Value& js, const char* postData)
161 Log* log = Log::getInstance();
162 log->log("JSONServer", Log::DEBUG, "recinfo");
164 char reqfilename[1000];
165 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
168 log->log("JSONServer", Log::ERR, "Could not decode filename");
169 js["Result"] = false;
170 js["Error"] = "Could not decode filename";
174 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
176 cRecordings Recordings;
177 Recordings.Load(); // probably have to do this
178 cRecording *recording = Recordings.GetByName(reqfilename);
182 log->log("JSONServer", Log::ERR, "recinfo found no recording");
183 js["Result"] = false;
187 js["IsNew"] = recording->IsNew();
188 js["LengthInSeconds"] = recording->LengthInSeconds();
189 js["FileSizeMB"] = recording->FileSizeMB();
190 js["Name"] = recording->Name() ? recording->Name() : Json::Value::null;
191 js["Priority"] = recording->Priority();
192 js["LifeTime"] = recording->Lifetime();
193 js["Start"] = (Json::UInt)recording->Start();
195 js["ResumePoint"] = 0;
196 cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
197 if (ResumeFile.Read() >= 0) js["ResumePoint"] = ResumeFile.Read();
199 js["CurrentlyRecordingStart"] = 0;
200 js["CurrentlyRecordingStop"] = 0;
201 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
204 js["CurrentlyRecordingStart"] = (Json::UInt)rc->Timer()->StartTime();
205 js["CurrentlyRecordingStop"] = (Json::UInt)rc->Timer()->StopTime();
208 const cRecordingInfo *info = recording->Info();
211 js["ChannelName"] = info->ChannelName() ? info->ChannelName() : Json::Value::null;
212 js["Title"] = info->Title() ? info->Title() : Json::Value::null;
213 js["ShortText"] = info->ShortText() ? info->ShortText() : Json::Value::null;
214 js["Description"] = info->Description() ? info->Description() : Json::Value::null;
216 const cComponents* components = info->Components();
219 js["Components"] = Json::Value::null;
223 Json::Value jscomponents;
225 tComponent* component;
226 for (int i = 0; i < components->NumComponents(); i++)
228 component = components->Component(i);
230 Json::Value oneComponent;
231 oneComponent["Stream"] = component->stream;
232 oneComponent["Type"] = component->type;
233 oneComponent["Language"] = component->language ? component->language : Json::Value::null;
234 oneComponent["Description"] = component->description ? component->description : Json::Value::null;
235 jscomponents.append(oneComponent);
238 js["Components"] = jscomponents;
246 bool jsonserver_recstop(Json::Value& js, const char* postData)
248 Log* log = Log::getInstance();
249 log->log("JSONServer", Log::DEBUG, "recstop");
251 char reqfilename[1000];
252 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
255 log->log("JSONServer", Log::ERR, "Could not decode filename");
256 js["Result"] = false;
257 js["Error"] = "Could not decode filename";
261 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
263 cRecordings Recordings;
264 Recordings.Load(); // probably have to do this
265 cRecording *recording = Recordings.GetByName(reqfilename);
269 log->log("JSONServer", Log::ERR, "recstop found no recording");
270 js["Result"] = false;
274 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
277 log->log("JSONServer", Log::ERR, "recstop - not currently recording");
278 js["Result"] = false;
282 if (Timers.BeingEdited())
284 log->log("JSONServer", Log::ERR, "recstop - timers being edited elsewhere");
285 js["Result"] = false;
289 cTimer* timer = rc->Timer();
292 log->log("JSONServer", Log::ERR, "recstop - timer not found");
293 js["Result"] = false;
297 timer->ClrFlags(tfActive);
298 Timers.SetModified();
304 bool jsonserver_recdel(Json::Value& js, const char* postData)
306 Log* log = Log::getInstance();
307 log->log("JSONServer", Log::DEBUG, "recdel");
309 char reqfilename[1000];
310 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
313 log->log("JSONServer", Log::ERR, "Could not decode filename");
314 js["Result"] = false;
315 js["Error"] = "Could not decode filename";
319 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
321 cRecordings Recordings;
322 Recordings.Load(); // probably have to do this
323 cRecording *recording = Recordings.GetByName(reqfilename);
327 js["Result"] = false;
328 js["Error"] = "Could not find recording to delete";
332 log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
333 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
336 js["Result"] = false;
337 js["Error"] = "This recording is still recording.. ho ho";
341 if (recording->Delete())
343 ::Recordings.DelByName(recording->FileName());
348 js["Result"] = false;
349 js["Error"] = "Failed to delete recording";
355 bool jsonserver_recmove(Json::Value& js, const char* postData)
357 Log* log = Log::getInstance();
358 log->log("JSONServer", Log::DEBUG, "recmove");
360 char* fileNameToMove = NULL;
361 char* requestedNewPath = NULL;
362 char* dateDirName = NULL;
363 char* titleDirName = NULL;
364 char* folderName = NULL;
365 char* newContainer = NULL;
370 int postDataLen = strlen(postData)+1;
371 fileNameToMove = new char[postDataLen];
372 int mgv1 = mg_get_var(postData, postDataLen-1, "filename", fileNameToMove, postDataLen);
373 requestedNewPath = new char[postDataLen];
374 int mgv2 = mg_get_var(postData, postDataLen-1, "newpath", requestedNewPath, postDataLen);
376 if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToMove) || !strlen(requestedNewPath))
378 log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
382 cRecordings Recordings;
383 Recordings.Load(); // probably have to do this
384 cRecording* recordingObj = Recordings.GetByName(fileNameToMove);
385 if (!recordingObj) throw 2;
387 cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
390 log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->Name());
391 log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->FileName());
392 log->log("JSONServer", Log::DEBUG, "to: %s", requestedNewPath);
394 const char* t = recordingObj->FileName();
398 // Find the datedirname
399 for(k = strlen(t) - 1; k >= 0; k--)
403 log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
404 dateDirName = new char[strlen(&t[k+1]) + 1];
405 strcpy(dateDirName, &t[k+1]);
410 // Find the titledirname
412 for(j = k-1; j >= 0; j--)
416 log->log("JSONServer", Log::DEBUG, "l2: %i", k - j);
417 titleDirName = new char[k - j];
418 memcpy(titleDirName, &t[j+1], k - j - 1);
419 titleDirName[k - j - 1] = '\0';
424 // Find the foldername
426 log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, strlen(VideoDirectory));
427 if (j > strlen(VideoDirectory)) // Rec is in a subfolder now
429 for(m = j-1; m >= 0; m--)
433 log->log("JSONServer", Log::DEBUG, "l3: %i", j - m);
434 folderName = new char[j - m];
435 memcpy(folderName, &t[m+1], j - m - 1);
436 folderName[j - m - 1] = '\0';
442 ExchangeChars(requestedNewPath, true);
444 log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
445 log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
446 log->log("JSONServer", Log::DEBUG, "viddir: %s", VideoDirectory);
447 if (folderName) log->log("JSONServer", Log::DEBUG, "folderName: %s", folderName);
448 log->log("JSONServer", Log::DEBUG, "EC: %s", requestedNewPath);
450 // Could be a new path - construct that first and test
451 newContainer = new char[strlen(VideoDirectory) + strlen(requestedNewPath) + strlen(titleDirName) + 1];
452 sprintf(newContainer, "%s%s", VideoDirectory, requestedNewPath);
453 log->log("JSONServer", Log::DEBUG, "NPT: %s", newContainer);
455 int statret = stat(newContainer, &dstat);
456 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
458 log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
459 int mkdirret = mkdir(newContainer, 0755);
460 if (mkdirret != 0) throw 4;
462 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
464 // Something exists but it's not a dir
468 // New path now created or was there already
470 sprintf(newContainer, "%s%s%s", VideoDirectory, requestedNewPath, titleDirName);
471 log->log("JSONServer", Log::DEBUG, "%s", newContainer);
473 statret = stat(newContainer, &dstat);
474 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
476 log->log("JSONServer", Log::DEBUG, "new dir does not exist (2)");
477 int mkdirret = mkdir(newContainer, 0755);
478 if (mkdirret != 0) throw 6;
480 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
482 // Something exists but it's not a dir
486 // Ok, the directory container has been made, or it pre-existed.
488 newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
489 sprintf(newDir, "%s/%s", newContainer, dateDirName);
491 log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
492 if (rename(t, newDir) != 0) throw 8;
494 // Success. Test for remove old dir containter
495 char* tempOldTitleDir = new char[k+1];
496 memcpy(tempOldTitleDir, t, k);
497 tempOldTitleDir[k] = '\0';
498 log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(tempOldTitleDir), tempOldTitleDir);
499 rmdir(tempOldTitleDir); // can't do anything about a fail result at this point.
500 delete[] tempOldTitleDir;
502 // Test for remove old foldername
505 char* tempOldFolderName = new char[j+1];
506 memcpy(tempOldFolderName, t, j);
507 tempOldFolderName[j] = '\0';
508 log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldfoldername: %s", j+1, j, strlen(tempOldFolderName), tempOldFolderName);
511 rmdir() deletes a directory, which must be empty.
512 ENOTEMPTY - pathname contains entries other than . and ..
513 So, should be safe to call rmdir on non-empty dir
515 rmdir(tempOldFolderName); // can't do anything about a fail result at this point.
516 delete[] tempOldFolderName;
519 ::Recordings.Update();
521 js["NewRecordingFileName"] = newDir;
525 js["Result"] = false;
528 log->log("JSONServer", Log::ERR, "Bad parameters");
529 js["Error"] = "Bad request parameters";
533 log->log("JSONServer", Log::ERR, "Could not find recording to move");
534 js["Error"] = "Bad filename";
538 log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
539 js["Error"] = "Cannot move recording in progress";
543 log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
544 js["Error"] = "Failed to create new directory (1)";
548 log->log("JSONServer", Log::ERR, "Something already exists? (1)");
549 js["Error"] = "Something already exists at the new path (1)";
553 log->log("JSONServer", Log::ERR, "Failed to make new dir (2)");
554 js["Error"] = "Failed to create new directory (2)";
558 log->log("JSONServer", Log::ERR, "Something already exists?");
559 js["Error"] = "Something already exists at the new path";
563 log->log("JSONServer", Log::ERR, "Rename failed");
564 js["Error"] = "Move failed";
568 if (fileNameToMove) delete[] fileNameToMove;
569 if (requestedNewPath) delete[] requestedNewPath;
570 if (dateDirName) delete[] dateDirName;
571 if (titleDirName) delete[] titleDirName;
572 if (folderName) delete[] folderName;
573 if (newContainer) delete[] newContainer;
574 if (newDir) delete[] newDir;
579 bool jsonserver_channellist(Json::Value& js)
581 Log* log = Log::getInstance();
582 log->log("JSONServer", Log::DEBUG, "channellist");
584 Json::Value jschannels;
587 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
589 if (!channel->GroupSep())
591 log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
593 if (channel->Vpid()) type = 1;
594 else if (channel->Apid(0)) type = 2;
597 Json::Value oneChannel;
598 oneChannel["Number"] = channel->Number();
599 oneChannel["Type"] = type;
600 oneChannel["Name"] = channel->Name();
601 #if VDRVERSNUM < 10703
602 oneChannel["VType"] = 2;
604 oneChannel["VType"] = channel->Vtype();
606 jschannels.append(oneChannel);
609 js["Channels"] = jschannels;
614 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
616 Log* log = Log::getInstance();
617 log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
619 char sChannelNumber[15]; int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);
620 char sStartTime[15]; int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);
621 char sDuration[15]; int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);
623 if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
625 log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
626 js["Result"] = false;
627 js["Error"] = "Bad request parameters";
631 int channelNumber = atoi(sChannelNumber);
632 int startTime = atoi(sStartTime);
633 int duration = atoi(sDuration);
635 cChannel* channel = NULL;
636 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
638 if (channel->GroupSep()) continue;
639 if (channel->Number() == channelNumber) break;
644 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
645 js["Result"] = false;
646 js["Error"] = "Could not find channel";
650 cSchedulesLock MutexLock;
651 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
654 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
655 js["Result"] = false;
656 js["Error"] = "Internal schedules error (1)";
659 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
662 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
663 js["Result"] = false;
664 js["Error"] = "Internal schedules error (2)";
668 Json::Value jsevents;
670 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
673 if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
675 if ((event->StartTime() + event->Duration()) <= startTime) continue;
677 if (event->StartTime() >= (startTime + duration)) continue;
679 Json::Value oneEvent;
680 oneEvent["ID"] = event->EventID();
681 oneEvent["Time"] = (Json::UInt)event->StartTime();
682 oneEvent["Duration"] = event->Duration();
683 oneEvent["Title"] = event->Title() ? event->Title() : "";
684 oneEvent["Description"] = event->Description() ? event->Description() : "";
685 jsevents.append(oneEvent);
688 js["Events"] = jsevents;
692 bool jsonserver_timerlist(Json::Value& js)
694 Log* log = Log::getInstance();
695 log->log("JSONServer", Log::DEBUG, "timerlist");
697 Json::Value jstimers;
700 int numTimers = Timers.Count();
702 for (int i = 0; i < numTimers; i++)
704 timer = Timers.Get(i);
705 Json::Value oneTimer;
706 oneTimer["Active"] = timer->HasFlags(tfActive);
707 oneTimer["Recording"] = timer->Recording();
708 oneTimer["Pending"] = timer->Pending();
709 oneTimer["Priority"] = timer->Priority();
710 oneTimer["Lifetime"] = timer->Lifetime();
711 oneTimer["ChannelNumber"] = timer->Channel()->Number();
712 oneTimer["StartTime"] = (int)timer->StartTime();
713 oneTimer["StopTime"] = (int)timer->StopTime();
714 oneTimer["Day"] = (int)timer->Day();
715 oneTimer["WeekDays"] = timer->WeekDays();
716 oneTimer["Name"] = timer->File();
717 jstimers.append(oneTimer);
720 js["Timers"] = jstimers;
724 bool jsonserver_timerdel(Json::Value& js, const char* postData)
726 Log* log = Log::getInstance();
727 log->log("JSONServer", Log::DEBUG, "timerdel");
729 char sdelChannel[15]; int mgv1 = mg_get_var(postData, strlen(postData), "delchannel", sdelChannel, 15);
730 char sdelWeekdays[15]; int mgv2 = mg_get_var(postData, strlen(postData), "delweekdays", sdelWeekdays, 15);
731 char sdelDay[15]; int mgv3 = mg_get_var(postData, strlen(postData), "delday", sdelDay, 15);
732 char sdelStart[15]; int mgv4 = mg_get_var(postData, strlen(postData), "delstart", sdelStart, 15);
733 char sdelStop[15]; int mgv5 = mg_get_var(postData, strlen(postData), "delstop", sdelStop, 15);
735 if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
737 log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
738 js["Result"] = false;
739 js["Error"] = "Bad request parameters";
743 int delChannel = atoi(sdelChannel);
744 int delWeekdays = atoi(sdelWeekdays);
745 int delDay = atoi(sdelDay);
746 int delStart = atoi(sdelStart);
747 int delStop = atoi(sdelStop);
750 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
752 if ( (ti->Channel()->Number() == delChannel)
753 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
754 && (ti->StartTime() == delStart)
755 && (ti->StopTime() == delStop) )
761 log->log("JSONServer", Log::ERR, "Could not find timer");
762 js["Result"] = false;
763 js["Error"] = "Could not find timer";
767 if (Timers.BeingEdited())
769 log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
770 js["Result"] = false;
771 js["Error"] = "Timers being edited at VDR";
777 log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
778 js["Result"] = false;
779 js["Error"] = "Timer is running";
784 Timers.SetModified();
790 bool jsonserver_timerset(Json::Value& js, const char* postData)
792 Log* log = Log::getInstance();
793 log->log("JSONServer", Log::DEBUG, "timerset");
795 char sTimerString[1024]; int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);
799 log->log("JSONServer", Log::ERR, "Could not get timerstring");
800 js["Result"] = false;
801 js["Error"] = "Bad request parameters";
805 log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
806 cTimer *timer = new cTimer;
807 if (!timer->Parse(sTimerString))
810 js["Result"] = false;
811 js["Error"] = "Failed to parse timer request details";
815 cTimer *t = Timers.GetTimer(timer);
819 js["Result"] = false;
820 js["Error"] = "Timer already exists";
825 Timers.SetModified();