]> git.vomp.tv Git - jsonserver.git/blob - handler.c
Add recording length to protocol
[jsonserver.git] / handler.c
1 #include "handler.h"
2
3 #include <string.h>
4 #include <stdlib.h>
5 #include <jsoncpp/json/json.h>
6 #include <string>
7
8 #include <vdr/videodir.h>
9 #include <vdr/recording.h>
10 #include <vdr/menu.h>
11 #include <vdr/timers.h>
12
13 #include "log.h"
14
15 int jsonserver_request_handler(struct mg_connection *conn)
16 {
17   Log* log = Log::getInstance();
18   const struct mg_request_info *request_info = mg_get_request_info(conn);
19   
20   if (strcmp(request_info->uri, "/jsonserver")) return 0; // not for us
21
22   char wvrequest[20];
23   int wvrl = mg_get_var(request_info->query_string, strlen(request_info->query_string), "req", wvrequest, 20);
24   if (wvrl == -1)
25   {
26     log->log("JSONServer", Log::ERR, "Could not decode req");
27     return 0;
28   }
29
30 /*
31   if (!strcmp(request_info->request_method, "OPTIONS"))
32   {
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");
36     return (void*)1;
37   }
38 */
39
40   // Get POST data
41   char postData[10000];
42   postData[0] = '\0';
43   if (!strcmp(request_info->request_method, "POST"))
44   {
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)
49     {
50       log->log("JSONServer", Log::DEBUG, "Length > 10000, rejecting");
51       return 0;
52     }
53
54     if (contentLengthI > 0)
55     {
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)
59       {
60         log->log("JSONServer", Log::DEBUG, "Could not read up to contentLength");
61         return 0;
62       }
63     }
64   }
65
66   Json::Value js;
67   bool success = false;
68
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);
78
79   if (!success) return 0; // the specific handler failed badly
80
81   // Now js will be filled
82
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());
88   return 1;
89
90   
91 /*
92   else if (event == MG_EVENT_LOG)
93   {
94     if (request_info->status_code == 400) // bad request
95     {
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++)
103       {
104         log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
105       }
106     }
107     else
108     {
109       log->log("Mongoose", Log::DEBUG, request_info->log_message);
110       log->log("Mongoose", Log::DEBUG, request_info->uri);
111     }
112     return (void*)1;
113   }
114   
115   // other events not handled:
116   // MG_HTTP_ERROR, MG_INIT_SSL
117   // Let mongoose do something with those
118
119   return NULL;
120
121 */
122   
123 }
124
125 bool jsonserver_reclist(Json::Value& js)
126 {
127   Log* log = Log::getInstance();
128   log->log("JSONServer", Log::DEBUG, "reclist");
129
130   int FreeMB;
131   int Percent = VideoDiskSpace(&FreeMB);
132   int Total = (FreeMB / (100 - Percent)) * 100;
133         
134   js["MBFree"] = FreeMB;
135   js["Percent"] = Percent;
136   js["Total"] = Total;
137   
138   Json::Value jsrecordings;
139   cRecordings Recordings;
140   Recordings.Load();
141   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
142   {
143     Json::Value oneRec;
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);
149   }
150   js["Recordings"] = jsrecordings;
151   
152   return true;
153 }
154
155 bool jsonserver_recinfo(Json::Value& js, const char* postData)
156 {
157   // For now this returns just the string summary of the recording
158
159   Log* log = Log::getInstance();
160   log->log("JSONServer", Log::DEBUG, "recinfo");
161
162   char reqfilename[1000];
163   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
164   if (mgv1 == -1)
165   {
166     log->log("JSONServer", Log::ERR, "Could not decode filename");
167     js["Result"] = false;
168     js["Error"] = "Could not decode filename";
169     return true;
170   }
171
172   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
173   
174   cRecordings Recordings;
175   Recordings.Load(); // probably have to do this
176   cRecording *recording = Recordings.GetByName(reqfilename);
177
178   if (recording)
179   {
180     const cRecordingInfo *Info = recording->Info();
181     char* summary = (char*)Info->ShortText();
182     if (isempty(summary)) summary = (char*)Info->Description();
183     js["Result"] = true;
184     js["Summary"] = summary;
185   }
186   else
187   {
188     log->log("JSONServer", Log::ERR, "recinfo found no recording");
189     js["Result"] = false;
190     js["Summary"] = "";
191   }  
192
193   return true;
194 }
195
196 bool jsonserver_recdel(Json::Value& js, const char* postData)
197 {
198   Log* log = Log::getInstance();
199   log->log("JSONServer", Log::DEBUG, "recdel");
200
201   char reqfilename[1000];
202   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
203   if (mgv1 == -1)
204   {
205     log->log("JSONServer", Log::ERR, "Could not decode filename");
206     js["Result"] = false;
207     js["Error"] = "Could not decode filename";
208     return true;
209   }
210
211   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
212   
213   cRecordings Recordings;
214   Recordings.Load(); // probably have to do this
215   cRecording *recording = Recordings.GetByName(reqfilename);
216
217   if (!recording)
218   {
219     js["Result"] = false;
220     js["Error"] = "Could not find recording to delete";
221     return true;
222   }
223
224   log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
225   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
226   if (rc)
227   {
228     js["Result"] = false;
229     js["Error"] = "This recording is still recording.. ho ho";
230     return true;
231   }
232
233   if (recording->Delete())
234   {
235     ::Recordings.DelByName(recording->FileName());
236     js["Result"] = true;
237   }
238   else
239   {
240     js["Result"] = false;
241     js["Error"] = "Failed to delete recording";
242   }
243
244   return true;
245 }
246
247 bool jsonserver_recmove(Json::Value& js, const char* postData)
248 {
249   Log* log = Log::getInstance();
250   log->log("JSONServer", Log::DEBUG, "recmove");
251
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);  
254
255   if ( (mgv1 == -1) || (mgv2 == -1) || !strlen(sFileName) || !strlen(sNewPath) )
256   {
257     log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
258     js["Result"] = false;
259     js["Error"] = "Bad request parameters";
260     return true;
261   }
262
263   cRecordings Recordings;
264   Recordings.Load(); // probably have to do this
265   cRecording* recording = Recordings.GetByName(sFileName);
266
267   if (!recording)
268   {
269     log->log("JSONServer", Log::ERR, "Could not find recording to move");
270     js["Result"] = false;
271     js["Error"] = "Bad filename";
272     return true;
273   }
274
275   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
276   if (rc)
277   {
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";
281     return true;
282   }
283   
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);
287
288   const char* t = recording->FileName();
289
290   char* dateDirName = NULL;   int k;
291   char* titleDirName = NULL;  int j;
292   char* newContainer = NULL;
293
294   // Find the datedirname
295   for(k = strlen(t) - 1; k >= 0; k--)
296   {
297     if (t[k] == '/')
298     {
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]);
302       break;
303     }
304   }
305
306   // Find the titledirname
307
308   for(j = k-1; j >= 0; j--)
309   {
310     if (t[j] == '/')
311     {
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';
316       break;
317     }
318   }
319
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);
323
324   ExchangeChars(sNewPath, true);
325   log->log("JSONServer", Log::DEBUG, "EC: %s", sNewPath);
326
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);
331
332   struct stat dstat;
333   int statret = stat(newContainer, &dstat);
334   if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
335   {
336     log->log("JSONServer", Log::DEBUG, "new dir does not exist");
337     int mkdirret = mkdir(newContainer, 0755);
338     if (mkdirret != 0)
339     {
340       delete[] dateDirName;
341       delete[] titleDirName;
342       delete[] newContainer;
343
344       log->log("JSONServer", Log::ERR, "Failed to make new dir");
345       js["Result"] = false;
346       js["Error"] = "Failed to create new directory";
347       return true;
348     }
349   }
350   else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
351   {
352     delete[] dateDirName;
353     delete[] titleDirName;
354     delete[] newContainer;
355
356     log->log("JSONServer", Log::ERR, "Something already exists?");
357     js["Result"] = false;
358     js["Error"] = "Something already exists at the new path";
359     return true;
360   }
361
362   // Ok, the directory container has been made, or it pre-existed.
363
364   char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
365   sprintf(newDir, "%s/%s", newContainer, dateDirName);
366
367   log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
368   int renameret = rename(t, newDir);
369   if (renameret == 0)
370   {
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;
378
379     ::Recordings.Update();
380     js["Result"] = true;
381   }
382   else
383   {
384     log->log("JSONServer", Log::ERR, "Rename failed");
385     js["Result"] = false;
386     js["Error"] = "Move failed";
387   }
388
389   delete[] dateDirName;
390   delete[] titleDirName;
391   delete[] newContainer;
392   delete[] newDir;
393
394   return true;
395 }
396
397 bool jsonserver_channellist(Json::Value& js)
398 {
399   Log* log = Log::getInstance();
400   log->log("JSONServer", Log::DEBUG, "channellist");
401
402   Json::Value jschannels;
403   
404   int type;
405   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
406   {
407     if (!channel->GroupSep())
408     {
409       log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
410
411       if (channel->Vpid()) type = 1;
412       else if (channel->Apid(0)) type = 2;
413       else continue;
414
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;
421 #else
422       oneChannel["VType"] = channel->Vtype();
423 #endif
424       jschannels.append(oneChannel);    
425     }
426   }
427   js["Channels"] = jschannels;
428   
429   return true;
430 }
431
432 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
433 {
434   Log* log = Log::getInstance();
435   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
436
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);  
440
441   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
442   {
443     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
444     js["Result"] = false;
445     js["Error"] = "Bad request parameters";
446     return true;
447   }
448
449   int channelNumber = atoi(sChannelNumber);
450   int startTime = atoi(sStartTime); 
451   int duration = atoi(sDuration); 
452
453   cChannel* channel = NULL;
454   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
455   {
456     if (channel->GroupSep()) continue;
457     if (channel->Number() == channelNumber) break;
458   }
459
460   if (!channel)
461   {
462     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
463     js["Result"] = false;
464     js["Error"] = "Could not find channel";
465     return true;
466   }
467
468   cSchedulesLock MutexLock;
469   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
470   if (!Schedules)
471   {
472     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
473     js["Result"] = false;
474     js["Error"] = "Internal schedules error (1)";
475     return true;
476   }
477   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
478   if (!Schedule)     
479   {
480     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
481     js["Result"] = false;
482     js["Error"] = "Internal schedules error (2)";
483     return true;
484   }
485     
486   Json::Value jsevents;
487
488   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
489   {
490     //in the past filter
491     if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
492    //start time filter
493     if ((event->StartTime() + event->Duration()) <= startTime) continue;
494     //duration filter
495     if (event->StartTime() >= (startTime + duration)) continue;
496
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);
504   }
505
506   js["Events"] = jsevents;
507   return true;
508 }
509
510 bool jsonserver_timerlist(Json::Value& js)
511 {
512   Log* log = Log::getInstance();
513   log->log("JSONServer", Log::DEBUG, "timerlist");
514
515   Json::Value jstimers;
516   
517   cTimer *timer;
518   int numTimers = Timers.Count();
519
520   for (int i = 0; i < numTimers; i++)
521   {
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);
536   }
537   
538   js["Timers"] = jstimers;
539   return true;
540 }
541
542 bool jsonserver_timerdel(Json::Value& js, const char* postData)
543 {
544   Log* log = Log::getInstance();
545   log->log("JSONServer", Log::DEBUG, "timerdel");
546
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);  
552
553   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
554   {
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";
558     return true;
559   }
560
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); 
566
567   cTimer* ti = NULL;
568   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
569   {
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) )
574        break;
575   }
576   
577   if (!ti)
578   {
579     log->log("JSONServer", Log::ERR, "Could not find timer");
580     js["Result"] = false;
581     js["Error"] = "Could not find timer";
582     return true;
583   }
584
585   if (Timers.BeingEdited())
586   {
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";
590     return true; 
591   }
592   
593   if (ti->Recording())
594   {
595     log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
596     js["Result"] = false;
597     js["Error"] = "Timer is running";
598     return true;
599   }
600   
601   Timers.Del(ti);
602   Timers.SetModified();
603   js["Result"] = true;
604     
605   return true;
606 }
607
608 bool jsonserver_timerset(Json::Value& js, const char* postData)
609 {
610   Log* log = Log::getInstance();
611   log->log("JSONServer", Log::DEBUG, "timerset");
612
613   char sTimerString[1024];   int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);  
614
615   if (mgv1 == -1)
616   {
617     log->log("JSONServer", Log::ERR, "Could not get timerstring");
618     js["Result"] = false;
619     js["Error"] = "Bad request parameters";
620     return true;
621   }
622
623   log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
624   cTimer *timer = new cTimer;
625   if (!timer->Parse(sTimerString))
626   {
627     delete timer;
628     js["Result"] = false;
629     js["Error"] = "Failed to parse timer request details";
630     return true;
631   }
632
633   cTimer *t = Timers.GetTimer(timer);
634   if (t)
635   {
636     delete timer;
637     js["Result"] = false;
638     js["Error"] = "Timer already exists";
639     return true;
640   }
641
642   Timers.Add(timer);
643   Timers.SetModified();
644   js["Result"] = true;
645   return true;
646 }
647