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");
69 if (!strcmp(wvrequest, "reclist")) success = jsonserver_reclist(js);
70 else if (!strcmp(wvrequest, "recinfo")) success = jsonserver_recinfo(js, postData);
71 else if (!strcmp(wvrequest, "recdel")) success = jsonserver_recdel(js, postData);
72 else if (!strcmp(wvrequest, "recmove")) success = jsonserver_recmove(js, postData);
73 else if (!strcmp(wvrequest, "channellist")) success = jsonserver_channellist(js);
74 else if (!strcmp(wvrequest, "channelschedule")) success = jsonserver_channelschedule(js, postData);
75 else if (!strcmp(wvrequest, "timerlist")) success = jsonserver_timerlist(js);
76 else if (!strcmp(wvrequest, "timerdel")) success = jsonserver_timerdel(js, postData);
77 else if (!strcmp(wvrequest, "timerset")) success = jsonserver_timerset(js, postData);
79 if (!success) return 0; // the specific handler failed badly
81 // Now js will be filled
83 Json::StyledWriter sw;
84 std::string jsonout = sw.write(js);
85 mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
86 mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
87 mg_write(conn, jsonout.c_str(), jsonout.length());
92 else if (event == MG_EVENT_LOG)
94 if (request_info->status_code == 400) // bad request
96 log->log("Mongoose", Log::DEBUG, "400 BAD REQUEST:");
97 log->log("Mongoose", Log::DEBUG, request_info->request_method);
98 log->log("Mongoose", Log::DEBUG, request_info->uri);
99 log->log("Mongoose", Log::DEBUG, request_info->http_version);
100 log->log("Mongoose", Log::DEBUG, request_info->query_string);
101 log->log("Mongoose", Log::DEBUG, request_info->log_message);
102 for (int i = 0; i < request_info->num_headers; i++)
104 log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
109 log->log("Mongoose", Log::DEBUG, request_info->log_message);
110 log->log("Mongoose", Log::DEBUG, request_info->uri);
115 // other events not handled:
116 // MG_HTTP_ERROR, MG_INIT_SSL
117 // Let mongoose do something with those
125 bool jsonserver_reclist(Json::Value& js)
127 Log* log = Log::getInstance();
128 log->log("JSONServer", Log::DEBUG, "reclist");
131 int Percent = VideoDiskSpace(&FreeMB);
132 int Total = (FreeMB / (100 - Percent)) * 100;
134 js["MBFree"] = FreeMB;
135 js["Percent"] = Percent;
138 Json::Value jsrecordings;
139 cRecordings Recordings;
141 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
144 oneRec["StartTime"] = (Json::UInt)recording->Start();
145 oneRec["Length"] = (Json::UInt)recording->LengthInSeconds();
146 oneRec["Name"] = recording->Name();
147 oneRec["Filename"] = recording->FileName();
148 jsrecordings.append(oneRec);
150 js["Recordings"] = jsrecordings;
155 bool jsonserver_recinfo(Json::Value& js, const char* postData)
157 // For now this returns just the string summary of the recording
159 Log* log = Log::getInstance();
160 log->log("JSONServer", Log::DEBUG, "recinfo");
162 char reqfilename[1000];
163 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
166 log->log("JSONServer", Log::ERR, "Could not decode filename");
167 js["Result"] = false;
168 js["Error"] = "Could not decode filename";
172 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
174 cRecordings Recordings;
175 Recordings.Load(); // probably have to do this
176 cRecording *recording = Recordings.GetByName(reqfilename);
180 const cRecordingInfo *Info = recording->Info();
181 char* summary = (char*)Info->ShortText();
182 if (isempty(summary)) summary = (char*)Info->Description();
184 js["Summary"] = summary;
188 log->log("JSONServer", Log::ERR, "recinfo found no recording");
189 js["Result"] = false;
196 bool jsonserver_recdel(Json::Value& js, const char* postData)
198 Log* log = Log::getInstance();
199 log->log("JSONServer", Log::DEBUG, "recdel");
201 char reqfilename[1000];
202 int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
205 log->log("JSONServer", Log::ERR, "Could not decode filename");
206 js["Result"] = false;
207 js["Error"] = "Could not decode filename";
211 log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
213 cRecordings Recordings;
214 Recordings.Load(); // probably have to do this
215 cRecording *recording = Recordings.GetByName(reqfilename);
219 js["Result"] = false;
220 js["Error"] = "Could not find recording to delete";
224 log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
225 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
228 js["Result"] = false;
229 js["Error"] = "This recording is still recording.. ho ho";
233 if (recording->Delete())
235 ::Recordings.DelByName(recording->FileName());
240 js["Result"] = false;
241 js["Error"] = "Failed to delete recording";
247 bool jsonserver_recmove(Json::Value& js, const char* postData)
249 Log* log = Log::getInstance();
250 log->log("JSONServer", Log::DEBUG, "recmove");
252 char sFileName[1000]; int mgv1 = mg_get_var(postData, strlen(postData), "filename", sFileName, 1000);
253 char sNewPath[1000]; int mgv2 = mg_get_var(postData, strlen(postData), "newpath", sNewPath, 1000);
255 if ( (mgv1 == -1) || (mgv2 == -1) || !strlen(sFileName) || !strlen(sNewPath) )
257 log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
258 js["Result"] = false;
259 js["Error"] = "Bad request parameters";
263 cRecordings Recordings;
264 Recordings.Load(); // probably have to do this
265 cRecording* recording = Recordings.GetByName(sFileName);
269 log->log("JSONServer", Log::ERR, "Could not find recording to move");
270 js["Result"] = false;
271 js["Error"] = "Bad filename";
275 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
278 log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
279 js["Result"] = false;
280 js["Error"] = "Cannot move recording in progress";
284 log->log("JSONServer", Log::DEBUG, "moving recording: %s", recording->Name());
285 log->log("JSONServer", Log::DEBUG, "moving recording: %s", recording->FileName());
286 log->log("JSONServer", Log::DEBUG, "to: %s", sNewPath);
288 const char* t = recording->FileName();
290 char* dateDirName = NULL; int k;
291 char* titleDirName = NULL; int j;
292 char* newContainer = NULL;
294 // Find the datedirname
295 for(k = strlen(t) - 1; k >= 0; k--)
299 log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
300 dateDirName = new char[strlen(&t[k+1]) + 1];
301 strcpy(dateDirName, &t[k+1]);
306 // Find the titledirname
308 for(j = k-1; j >= 0; j--)
312 log->log("JSONServer", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
313 titleDirName = new char[(k - j - 1) + 1];
314 memcpy(titleDirName, &t[j+1], k - j - 1);
315 titleDirName[k - j - 1] = '\0';
320 log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
321 log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
322 log->log("JSONServer", Log::DEBUG, "viddir: %s", VideoDirectory);
324 ExchangeChars(sNewPath, true);
325 log->log("JSONServer", Log::DEBUG, "EC: %s", sNewPath);
327 newContainer = new char[strlen(VideoDirectory) + strlen(sNewPath) + strlen(titleDirName) + 1];
328 log->log("JSONServer", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(sNewPath) + strlen(titleDirName) + 1);
329 sprintf(newContainer, "%s%s%s", VideoDirectory, sNewPath, titleDirName);
330 log->log("JSONServer", Log::DEBUG, "%s", newContainer);
333 int statret = stat(newContainer, &dstat);
334 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
336 log->log("JSONServer", Log::DEBUG, "new dir does not exist");
337 int mkdirret = mkdir(newContainer, 0755);
340 delete[] dateDirName;
341 delete[] titleDirName;
342 delete[] newContainer;
344 log->log("JSONServer", Log::ERR, "Failed to make new dir");
345 js["Result"] = false;
346 js["Error"] = "Failed to create new directory";
350 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
352 delete[] dateDirName;
353 delete[] titleDirName;
354 delete[] newContainer;
356 log->log("JSONServer", Log::ERR, "Something already exists?");
357 js["Result"] = false;
358 js["Error"] = "Something already exists at the new path";
362 // Ok, the directory container has been made, or it pre-existed.
364 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
365 sprintf(newDir, "%s/%s", newContainer, dateDirName);
367 log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
368 int renameret = rename(t, newDir);
371 // Success. Test for remove old dir containter
372 char* oldTitleDir = new char[k+1];
373 memcpy(oldTitleDir, t, k);
374 oldTitleDir[k] = '\0';
375 log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
376 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
377 delete[] oldTitleDir;
379 ::Recordings.Update();
384 log->log("JSONServer", Log::ERR, "Rename failed");
385 js["Result"] = false;
386 js["Error"] = "Move failed";
389 delete[] dateDirName;
390 delete[] titleDirName;
391 delete[] newContainer;
397 bool jsonserver_channellist(Json::Value& js)
399 Log* log = Log::getInstance();
400 log->log("JSONServer", Log::DEBUG, "channellist");
402 Json::Value jschannels;
405 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
407 if (!channel->GroupSep())
409 log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
411 if (channel->Vpid()) type = 1;
412 else if (channel->Apid(0)) type = 2;
415 Json::Value oneChannel;
416 oneChannel["Number"] = channel->Number();
417 oneChannel["Type"] = type;
418 oneChannel["Name"] = channel->Name();
419 #if VDRVERSNUM < 10703
420 oneChannel["VType"] = 2;
422 oneChannel["VType"] = channel->Vtype();
424 jschannels.append(oneChannel);
427 js["Channels"] = jschannels;
432 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
434 Log* log = Log::getInstance();
435 log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
437 char sChannelNumber[15]; int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);
438 char sStartTime[15]; int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);
439 char sDuration[15]; int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);
441 if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
443 log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
444 js["Result"] = false;
445 js["Error"] = "Bad request parameters";
449 int channelNumber = atoi(sChannelNumber);
450 int startTime = atoi(sStartTime);
451 int duration = atoi(sDuration);
453 cChannel* channel = NULL;
454 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
456 if (channel->GroupSep()) continue;
457 if (channel->Number() == channelNumber) break;
462 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
463 js["Result"] = false;
464 js["Error"] = "Could not find channel";
468 cSchedulesLock MutexLock;
469 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
472 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
473 js["Result"] = false;
474 js["Error"] = "Internal schedules error (1)";
477 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
480 log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
481 js["Result"] = false;
482 js["Error"] = "Internal schedules error (2)";
486 Json::Value jsevents;
488 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
491 if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
493 if ((event->StartTime() + event->Duration()) <= startTime) continue;
495 if (event->StartTime() >= (startTime + duration)) continue;
497 Json::Value oneEvent;
498 oneEvent["ID"] = event->EventID();
499 oneEvent["Time"] = (Json::UInt)event->StartTime();
500 oneEvent["Duration"] = event->Duration();
501 oneEvent["Title"] = event->Title() ? event->Title() : "";
502 oneEvent["Description"] = event->Description() ? event->Description() : "";
503 jsevents.append(oneEvent);
506 js["Events"] = jsevents;
510 bool jsonserver_timerlist(Json::Value& js)
512 Log* log = Log::getInstance();
513 log->log("JSONServer", Log::DEBUG, "timerlist");
515 Json::Value jstimers;
518 int numTimers = Timers.Count();
520 for (int i = 0; i < numTimers; i++)
522 timer = Timers.Get(i);
523 Json::Value oneTimer;
524 oneTimer["Active"] = timer->HasFlags(tfActive);
525 oneTimer["Recording"] = timer->Recording();
526 oneTimer["Pending"] = timer->Pending();
527 oneTimer["Priority"] = timer->Priority();
528 oneTimer["Lifetime"] = timer->Lifetime();
529 oneTimer["ChannelNumber"] = timer->Channel()->Number();
530 oneTimer["StartTime"] = (int)timer->StartTime();
531 oneTimer["StopTime"] = (int)timer->StopTime();
532 oneTimer["Day"] = (int)timer->Day();
533 oneTimer["WeekDays"] = timer->WeekDays();
534 oneTimer["Name"] = timer->File();
535 jstimers.append(oneTimer);
538 js["Timers"] = jstimers;
542 bool jsonserver_timerdel(Json::Value& js, const char* postData)
544 Log* log = Log::getInstance();
545 log->log("JSONServer", Log::DEBUG, "timerdel");
547 char sdelChannel[15]; int mgv1 = mg_get_var(postData, strlen(postData), "delchannel", sdelChannel, 15);
548 char sdelWeekdays[15]; int mgv2 = mg_get_var(postData, strlen(postData), "delweekdays", sdelWeekdays, 15);
549 char sdelDay[15]; int mgv3 = mg_get_var(postData, strlen(postData), "delday", sdelDay, 15);
550 char sdelStart[15]; int mgv4 = mg_get_var(postData, strlen(postData), "delstart", sdelStart, 15);
551 char sdelStop[15]; int mgv5 = mg_get_var(postData, strlen(postData), "delstop", sdelStop, 15);
553 if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
555 log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
556 js["Result"] = false;
557 js["Error"] = "Bad request parameters";
561 int delChannel = atoi(sdelChannel);
562 int delWeekdays = atoi(sdelWeekdays);
563 int delDay = atoi(sdelDay);
564 int delStart = atoi(sdelStart);
565 int delStop = atoi(sdelStop);
568 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
570 if ( (ti->Channel()->Number() == delChannel)
571 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
572 && (ti->StartTime() == delStart)
573 && (ti->StopTime() == delStop) )
579 log->log("JSONServer", Log::ERR, "Could not find timer");
580 js["Result"] = false;
581 js["Error"] = "Could not find timer";
585 if (Timers.BeingEdited())
587 log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
588 js["Result"] = false;
589 js["Error"] = "Timers being edited at VDR";
595 log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
596 js["Result"] = false;
597 js["Error"] = "Timer is running";
602 Timers.SetModified();
608 bool jsonserver_timerset(Json::Value& js, const char* postData)
610 Log* log = Log::getInstance();
611 log->log("JSONServer", Log::DEBUG, "timerset");
613 char sTimerString[1024]; int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);
617 log->log("JSONServer", Log::ERR, "Could not get timerstring");
618 js["Result"] = false;
619 js["Error"] = "Bad request parameters";
623 log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
624 cTimer *timer = new cTimer;
625 if (!timer->Parse(sTimerString))
628 js["Result"] = false;
629 js["Error"] = "Failed to parse timer request details";
633 cTimer *t = Timers.GetTimer(timer);
637 js["Result"] = false;
638 js["Error"] = "Timer already exists";
643 Timers.SetModified();