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 jsrecordings.append(oneRec);
153 js["Recordings"] = jsrecordings;
158 bool jsonserver_recinfo(Json::Value& js, const char* postData)
160 Log* log = Log::getInstance();
161 log->log("JSONServer", Log::DEBUG, "recinfo");
163 char reqfilename[1000];
164 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
167 log->log("JSONServer", Log::ERR, "Could not decode filename");
168 js["Result"] = false;
169 js["Error"] = "Could not decode filename";
173 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
175 cRecordings Recordings;
176 Recordings.Load(); // probably have to do this
177 cRecording *recording = Recordings.GetByName(reqfilename);
181 log->log("JSONServer", Log::ERR, "recinfo found no recording");
182 js["Result"] = false;
186 js["IsNew"] = recording->IsNew();
187 js["LengthInSeconds"] = recording->LengthInSeconds();
188 js["FileSizeMB"] = recording->FileSizeMB();
189 js["Name"] = recording->Name() ? recording->Name() : Json::Value::null;
190 js["Priority"] = recording->Priority();
191 js["LifeTime"] = recording->Lifetime();
192 js["Start"] = (Json::UInt)recording->Start();
194 js["ResumePoint"] = 0;
195 cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
196 if (ResumeFile.Read() >= 0) js["ResumePoint"] = ResumeFile.Read();
198 js["CurrentlyRecordingStart"] = 0;
199 js["CurrentlyRecordingStop"] = 0;
200 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
203 js["CurrentlyRecordingStart"] = (Json::UInt)rc->Timer()->StartTime();
204 js["CurrentlyRecordingStop"] = (Json::UInt)rc->Timer()->StopTime();
207 const cRecordingInfo *info = recording->Info();
210 js["ChannelName"] = info->ChannelName() ? info->ChannelName() : Json::Value::null;
211 js["Title"] = info->Title() ? info->Title() : Json::Value::null;
212 js["ShortText"] = info->ShortText() ? info->ShortText() : Json::Value::null;
213 js["Description"] = info->Description() ? info->Description() : Json::Value::null;
215 const cComponents* components = info->Components();
218 js["Components"] = Json::Value::null;
222 Json::Value jscomponents;
224 tComponent* component;
225 for (int i = 0; i < components->NumComponents(); i++)
227 component = components->Component(i);
229 Json::Value oneComponent;
230 oneComponent["Stream"] = component->stream;
231 oneComponent["Type"] = component->type;
232 oneComponent["Language"] = component->language ? component->language : Json::Value::null;
233 oneComponent["Description"] = component->description ? component->description : Json::Value::null;
234 jscomponents.append(oneComponent);
237 js["Components"] = jscomponents;
245 bool jsonserver_recstop(Json::Value& js, const char* postData)
247 Log* log = Log::getInstance();
248 log->log("JSONServer", Log::DEBUG, "recstop");
250 char reqfilename[1000];
251 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
254 log->log("JSONServer", Log::ERR, "Could not decode filename");
255 js["Result"] = false;
256 js["Error"] = "Could not decode filename";
260 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
262 cRecordings Recordings;
263 Recordings.Load(); // probably have to do this
264 cRecording *recording = Recordings.GetByName(reqfilename);
268 log->log("JSONServer", Log::ERR, "recstop found no recording");
269 js["Result"] = false;
273 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
276 log->log("JSONServer", Log::ERR, "recstop - not currently recording");
277 js["Result"] = false;
281 if (Timers.BeingEdited())
283 log->log("JSONServer", Log::ERR, "recstop - timers being edited elsewhere");
284 js["Result"] = false;
288 cTimer* timer = rc->Timer();
291 log->log("JSONServer", Log::ERR, "recstop - timer not found");
292 js["Result"] = false;
296 timer->ClrFlags(tfActive);
297 Timers.SetModified();
303 bool jsonserver_recdel(Json::Value& js, const char* postData)
305 Log* log = Log::getInstance();
306 log->log("JSONServer", Log::DEBUG, "recdel");
308 char reqfilename[1000];
309 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
312 log->log("JSONServer", Log::ERR, "Could not decode filename");
313 js["Result"] = false;
314 js["Error"] = "Could not decode filename";
318 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
320 cRecordings Recordings;
321 Recordings.Load(); // probably have to do this
322 cRecording *recording = Recordings.GetByName(reqfilename);
326 js["Result"] = false;
327 js["Error"] = "Could not find recording to delete";
331 log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
332 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
335 js["Result"] = false;
336 js["Error"] = "This recording is still recording.. ho ho";
340 if (recording->Delete())
342 ::Recordings.DelByName(recording->FileName());
347 js["Result"] = false;
348 js["Error"] = "Failed to delete recording";
354 bool jsonserver_recmove(Json::Value& js, const char* postData)
356 Log* log = Log::getInstance();
357 log->log("JSONServer", Log::DEBUG, "recmove");
359 char* fileNameToMove = NULL;
360 char* requestedNewPath = NULL;
361 char* dateDirName = NULL;
362 char* titleDirName = NULL;
363 char* folderName = NULL;
364 char* newContainer = NULL;
369 int postDataLen = strlen(postData)+1;
370 fileNameToMove = new char[postDataLen];
371 int mgv1 = mg_get_var(postData, postDataLen-1, "filename", fileNameToMove, postDataLen);
372 requestedNewPath = new char[postDataLen];
373 int mgv2 = mg_get_var(postData, postDataLen-1, "newpath", requestedNewPath, postDataLen);
375 if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToMove) || !strlen(requestedNewPath))
377 log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
381 cRecordings Recordings;
382 Recordings.Load(); // probably have to do this
383 cRecording* recordingObj = Recordings.GetByName(fileNameToMove);
384 if (!recordingObj) throw 2;
386 cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
389 log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->Name());
390 log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->FileName());
391 log->log("JSONServer", Log::DEBUG, "to: %s", requestedNewPath);
393 const char* t = recordingObj->FileName();
397 // Find the datedirname
398 for(k = strlen(t) - 1; k >= 0; k--)
402 log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
403 dateDirName = new char[strlen(&t[k+1]) + 1];
404 strcpy(dateDirName, &t[k+1]);
409 // Find the titledirname
411 for(j = k-1; j >= 0; j--)
415 log->log("JSONServer", Log::DEBUG, "l2: %i", k - j);
416 titleDirName = new char[k - j];
417 memcpy(titleDirName, &t[j+1], k - j - 1);
418 titleDirName[k - j - 1] = '\0';
423 // Find the foldername
425 log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, strlen(VideoDirectory));
426 if (j > strlen(VideoDirectory)) // Rec is in a subfolder now
428 for(m = j-1; m >= 0; m--)
432 log->log("JSONServer", Log::DEBUG, "l3: %i", j - m);
433 folderName = new char[j - m];
434 memcpy(folderName, &t[m+1], j - m - 1);
435 folderName[j - m - 1] = '\0';
441 ExchangeChars(requestedNewPath, true);
443 log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
444 log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
445 log->log("JSONServer", Log::DEBUG, "viddir: %s", VideoDirectory);
446 if (folderName) log->log("JSONServer", Log::DEBUG, "folderName: %s", folderName);
447 log->log("JSONServer", Log::DEBUG, "EC: %s", requestedNewPath);
449 // Could be a new path - construct that first and test
450 newContainer = new char[strlen(VideoDirectory) + strlen(requestedNewPath) + strlen(titleDirName) + 1];
451 sprintf(newContainer, "%s%s", VideoDirectory, requestedNewPath);
452 log->log("JSONServer", Log::DEBUG, "NPT: %s", newContainer);
454 int statret = stat(newContainer, &dstat);
455 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
457 log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
458 int mkdirret = mkdir(newContainer, 0755);
459 if (mkdirret != 0) throw 4;
461 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
463 // Something exists but it's not a dir
467 // New path now created or was there already
469 sprintf(newContainer, "%s%s%s", VideoDirectory, requestedNewPath, titleDirName);
470 log->log("JSONServer", Log::DEBUG, "%s", newContainer);
472 statret = stat(newContainer, &dstat);
473 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
475 log->log("JSONServer", Log::DEBUG, "new dir does not exist (2)");
476 int mkdirret = mkdir(newContainer, 0755);
477 if (mkdirret != 0) throw 6;
479 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
481 // Something exists but it's not a dir
485 // Ok, the directory container has been made, or it pre-existed.
487 newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
488 sprintf(newDir, "%s/%s", newContainer, dateDirName);
490 log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
491 if (rename(t, newDir) != 0) throw 8;
493 // Success. Test for remove old dir containter
494 char* tempOldTitleDir = new char[k+1];
495 memcpy(tempOldTitleDir, t, k);
496 tempOldTitleDir[k] = '\0';
497 log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(tempOldTitleDir), tempOldTitleDir);
498 rmdir(tempOldTitleDir); // can't do anything about a fail result at this point.
499 delete[] tempOldTitleDir;
501 // Test for remove old foldername
504 char* tempOldFolderName = new char[j+1];
505 memcpy(tempOldFolderName, t, j);
506 tempOldFolderName[j] = '\0';
507 log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldfoldername: %s", j+1, j, strlen(tempOldFolderName), tempOldFolderName);
510 rmdir() deletes a directory, which must be empty.
511 ENOTEMPTY - pathname contains entries other than . and ..
512 So, should be safe to call rmdir on non-empty dir
514 rmdir(tempOldFolderName); // can't do anything about a fail result at this point.
515 delete[] tempOldFolderName;
518 ::Recordings.Update();
520 js["NewRecordingFileName"] = newDir;
524 js["Result"] = false;
527 log->log("JSONServer", Log::ERR, "Bad parameters");
528 js["Error"] = "Bad request parameters";
532 log->log("JSONServer", Log::ERR, "Could not find recording to move");
533 js["Error"] = "Bad filename";
537 log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
538 js["Error"] = "Cannot move recording in progress";
542 log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
543 js["Error"] = "Failed to create new directory (1)";
547 log->log("JSONServer", Log::ERR, "Something already exists? (1)");
548 js["Error"] = "Something already exists at the new path (1)";
552 log->log("JSONServer", Log::ERR, "Failed to make new dir (2)");
553 js["Error"] = "Failed to create new directory (2)";
557 log->log("JSONServer", Log::ERR, "Something already exists?");
558 js["Error"] = "Something already exists at the new path";
562 log->log("JSONServer", Log::ERR, "Rename failed");
563 js["Error"] = "Move failed";
567 if (fileNameToMove) delete[] fileNameToMove;
568 if (requestedNewPath) delete[] requestedNewPath;
569 if (dateDirName) delete[] dateDirName;
570 if (titleDirName) delete[] titleDirName;
571 if (folderName) delete[] folderName;
572 if (newContainer) delete[] newContainer;
573 if (newDir) delete[] newDir;
578 bool jsonserver_channellist(Json::Value& js)
580 Log* log = Log::getInstance();
581 log->log("JSONServer", Log::DEBUG, "channellist");
583 Json::Value jschannels;
586 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
588 if (!channel->GroupSep())
590 log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
592 if (channel->Vpid()) type = 1;
593 else if (channel->Apid(0)) type = 2;
596 Json::Value oneChannel;
597 oneChannel["Number"] = channel->Number();
598 oneChannel["Type"] = type;
599 oneChannel["Name"] = channel->Name();
600 #if VDRVERSNUM < 10703
601 oneChannel["VType"] = 2;
603 oneChannel["VType"] = channel->Vtype();
605 jschannels.append(oneChannel);
608 js["Channels"] = jschannels;
613 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
615 Log* log = Log::getInstance();
616 log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
618 char sChannelNumber[15]; int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);
619 char sStartTime[15]; int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);
620 char sDuration[15]; int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);
622 if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
624 log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
625 js["Result"] = false;
626 js["Error"] = "Bad request parameters";
630 int channelNumber = atoi(sChannelNumber);
631 int startTime = atoi(sStartTime);
632 int duration = atoi(sDuration);
634 cChannel* channel = NULL;
635 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
637 if (channel->GroupSep()) continue;
638 if (channel->Number() == channelNumber) break;
643 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
644 js["Result"] = false;
645 js["Error"] = "Could not find channel";
649 cSchedulesLock MutexLock;
650 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
653 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
654 js["Result"] = false;
655 js["Error"] = "Internal schedules error (1)";
658 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
661 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
662 js["Result"] = false;
663 js["Error"] = "Internal schedules error (2)";
667 Json::Value jsevents;
669 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
672 if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
674 if ((event->StartTime() + event->Duration()) <= startTime) continue;
676 if (event->StartTime() >= (startTime + duration)) continue;
678 Json::Value oneEvent;
679 oneEvent["ID"] = event->EventID();
680 oneEvent["Time"] = (Json::UInt)event->StartTime();
681 oneEvent["Duration"] = event->Duration();
682 oneEvent["Title"] = event->Title() ? event->Title() : "";
683 oneEvent["Description"] = event->Description() ? event->Description() : "";
684 jsevents.append(oneEvent);
687 js["Events"] = jsevents;
691 bool jsonserver_timerlist(Json::Value& js)
693 Log* log = Log::getInstance();
694 log->log("JSONServer", Log::DEBUG, "timerlist");
696 Json::Value jstimers;
699 int numTimers = Timers.Count();
701 for (int i = 0; i < numTimers; i++)
703 timer = Timers.Get(i);
704 Json::Value oneTimer;
705 oneTimer["Active"] = timer->HasFlags(tfActive);
706 oneTimer["Recording"] = timer->Recording();
707 oneTimer["Pending"] = timer->Pending();
708 oneTimer["Priority"] = timer->Priority();
709 oneTimer["Lifetime"] = timer->Lifetime();
710 oneTimer["ChannelNumber"] = timer->Channel()->Number();
711 oneTimer["StartTime"] = (int)timer->StartTime();
712 oneTimer["StopTime"] = (int)timer->StopTime();
713 oneTimer["Day"] = (int)timer->Day();
714 oneTimer["WeekDays"] = timer->WeekDays();
715 oneTimer["Name"] = timer->File();
716 jstimers.append(oneTimer);
719 js["Timers"] = jstimers;
723 bool jsonserver_timerdel(Json::Value& js, const char* postData)
725 Log* log = Log::getInstance();
726 log->log("JSONServer", Log::DEBUG, "timerdel");
728 char sdelChannel[15]; int mgv1 = mg_get_var(postData, strlen(postData), "delchannel", sdelChannel, 15);
729 char sdelWeekdays[15]; int mgv2 = mg_get_var(postData, strlen(postData), "delweekdays", sdelWeekdays, 15);
730 char sdelDay[15]; int mgv3 = mg_get_var(postData, strlen(postData), "delday", sdelDay, 15);
731 char sdelStart[15]; int mgv4 = mg_get_var(postData, strlen(postData), "delstart", sdelStart, 15);
732 char sdelStop[15]; int mgv5 = mg_get_var(postData, strlen(postData), "delstop", sdelStop, 15);
734 if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
736 log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
737 js["Result"] = false;
738 js["Error"] = "Bad request parameters";
742 int delChannel = atoi(sdelChannel);
743 int delWeekdays = atoi(sdelWeekdays);
744 int delDay = atoi(sdelDay);
745 int delStart = atoi(sdelStart);
746 int delStop = atoi(sdelStop);
749 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
751 if ( (ti->Channel()->Number() == delChannel)
752 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
753 && (ti->StartTime() == delStart)
754 && (ti->StopTime() == delStop) )
760 log->log("JSONServer", Log::ERR, "Could not find timer");
761 js["Result"] = false;
762 js["Error"] = "Could not find timer";
766 if (Timers.BeingEdited())
768 log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
769 js["Result"] = false;
770 js["Error"] = "Timers being edited at VDR";
776 log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
777 js["Result"] = false;
778 js["Error"] = "Timer is running";
783 Timers.SetModified();
789 bool jsonserver_timerset(Json::Value& js, const char* postData)
791 Log* log = Log::getInstance();
792 log->log("JSONServer", Log::DEBUG, "timerset");
794 char sTimerString[1024]; int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);
798 log->log("JSONServer", Log::ERR, "Could not get timerstring");
799 js["Result"] = false;
800 js["Error"] = "Bad request parameters";
804 log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
805 cTimer *timer = new cTimer;
806 if (!timer->Parse(sTimerString))
809 js["Result"] = false;
810 js["Error"] = "Failed to parse timer request details";
814 cTimer *t = Timers.GetTimer(timer);
818 js["Result"] = false;
819 js["Error"] = "Timer already exists";
824 Timers.SetModified();