]> git.vomp.tv Git - jsonserver.git/blob - handler.c
add IsNew to recordings
[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["IsNew"] = recording->IsNew();
147     oneRec["Name"] = recording->Name();
148     oneRec["Filename"] = recording->FileName();
149     jsrecordings.append(oneRec);
150   }
151   js["Recordings"] = jsrecordings;
152   
153   return true;
154 }
155
156 bool jsonserver_recinfo(Json::Value& js, const char* postData)
157 {
158   // For now this returns just the string summary of the recording
159
160   Log* log = Log::getInstance();
161   log->log("JSONServer", Log::DEBUG, "recinfo");
162
163   char reqfilename[1000];
164   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
165   if (mgv1 == -1)
166   {
167     log->log("JSONServer", Log::ERR, "Could not decode filename");
168     js["Result"] = false;
169     js["Error"] = "Could not decode filename";
170     return true;
171   }
172
173   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
174   
175   cRecordings Recordings;
176   Recordings.Load(); // probably have to do this
177   cRecording *recording = Recordings.GetByName(reqfilename);
178
179   if (recording)
180   {
181     const cRecordingInfo *Info = recording->Info();
182     char* summary = (char*)Info->ShortText();
183     if (isempty(summary)) summary = (char*)Info->Description();
184     js["Result"] = true;
185     js["Summary"] = summary;
186   }
187   else
188   {
189     log->log("JSONServer", Log::ERR, "recinfo found no recording");
190     js["Result"] = false;
191     js["Summary"] = "";
192   }  
193
194   return true;
195 }
196
197 bool jsonserver_recdel(Json::Value& js, const char* postData)
198 {
199   Log* log = Log::getInstance();
200   log->log("JSONServer", Log::DEBUG, "recdel");
201
202   char reqfilename[1000];
203   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
204   if (mgv1 == -1)
205   {
206     log->log("JSONServer", Log::ERR, "Could not decode filename");
207     js["Result"] = false;
208     js["Error"] = "Could not decode filename";
209     return true;
210   }
211
212   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
213   
214   cRecordings Recordings;
215   Recordings.Load(); // probably have to do this
216   cRecording *recording = Recordings.GetByName(reqfilename);
217
218   if (!recording)
219   {
220     js["Result"] = false;
221     js["Error"] = "Could not find recording to delete";
222     return true;
223   }
224
225   log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
226   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
227   if (rc)
228   {
229     js["Result"] = false;
230     js["Error"] = "This recording is still recording.. ho ho";
231     return true;
232   }
233
234   if (recording->Delete())
235   {
236     ::Recordings.DelByName(recording->FileName());
237     js["Result"] = true;
238   }
239   else
240   {
241     js["Result"] = false;
242     js["Error"] = "Failed to delete recording";
243   }
244
245   return true;
246 }
247
248 bool jsonserver_recmove(Json::Value& js, const char* postData)
249 {
250   Log* log = Log::getInstance();
251   log->log("JSONServer", Log::DEBUG, "recmove");
252
253   char sFileName[1000]; int mgv1 = mg_get_var(postData, strlen(postData), "filename", sFileName, 1000);  
254   char sNewPath[1000];  int mgv2 = mg_get_var(postData, strlen(postData), "newpath", sNewPath, 1000);  
255
256   if ( (mgv1 == -1) || (mgv2 == -1) || !strlen(sFileName) || !strlen(sNewPath) )
257   {
258     log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
259     js["Result"] = false;
260     js["Error"] = "Bad request parameters";
261     return true;
262   }
263
264   cRecordings Recordings;
265   Recordings.Load(); // probably have to do this
266   cRecording* recording = Recordings.GetByName(sFileName);
267
268   if (!recording)
269   {
270     log->log("JSONServer", Log::ERR, "Could not find recording to move");
271     js["Result"] = false;
272     js["Error"] = "Bad filename";
273     return true;
274   }
275
276   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
277   if (rc)
278   {
279     log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
280     js["Result"] = false;
281     js["Error"] = "Cannot move recording in progress";
282     return true;
283   }
284   
285   log->log("JSONServer", Log::DEBUG, "moving recording: %s", recording->Name());
286   log->log("JSONServer", Log::DEBUG, "moving recording: %s", recording->FileName());
287   log->log("JSONServer", Log::DEBUG, "to: %s", sNewPath);
288
289   const char* t = recording->FileName();
290
291   char* dateDirName = NULL;   int k;
292   char* titleDirName = NULL;  int j;
293   char* newContainer = NULL;
294
295   // Find the datedirname
296   for(k = strlen(t) - 1; k >= 0; k--)
297   {
298     if (t[k] == '/')
299     {
300       log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
301       dateDirName = new char[strlen(&t[k+1]) + 1];
302       strcpy(dateDirName, &t[k+1]);
303       break;
304     }
305   }
306
307   // Find the titledirname
308
309   for(j = k-1; j >= 0; j--)
310   {
311     if (t[j] == '/')
312     {
313       log->log("JSONServer", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
314       titleDirName = new char[(k - j - 1) + 1];
315       memcpy(titleDirName, &t[j+1], k - j - 1);
316       titleDirName[k - j - 1] = '\0';
317       break;
318     }
319   }
320
321   log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
322   log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
323   log->log("JSONServer", Log::DEBUG, "viddir: %s", VideoDirectory);
324
325   ExchangeChars(sNewPath, true);
326   log->log("JSONServer", Log::DEBUG, "EC: %s", sNewPath);
327
328   newContainer = new char[strlen(VideoDirectory) + strlen(sNewPath) + strlen(titleDirName) + 1];
329   log->log("JSONServer", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(sNewPath) + strlen(titleDirName) + 1);
330   sprintf(newContainer, "%s%s%s", VideoDirectory, sNewPath, titleDirName);
331   log->log("JSONServer", Log::DEBUG, "%s", newContainer);
332
333   struct stat dstat;
334   int statret = stat(newContainer, &dstat);
335   if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
336   {
337     log->log("JSONServer", Log::DEBUG, "new dir does not exist");
338     int mkdirret = mkdir(newContainer, 0755);
339     if (mkdirret != 0)
340     {
341       delete[] dateDirName;
342       delete[] titleDirName;
343       delete[] newContainer;
344
345       log->log("JSONServer", Log::ERR, "Failed to make new dir");
346       js["Result"] = false;
347       js["Error"] = "Failed to create new directory";
348       return true;
349     }
350   }
351   else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
352   {
353     delete[] dateDirName;
354     delete[] titleDirName;
355     delete[] newContainer;
356
357     log->log("JSONServer", Log::ERR, "Something already exists?");
358     js["Result"] = false;
359     js["Error"] = "Something already exists at the new path";
360     return true;
361   }
362
363   // Ok, the directory container has been made, or it pre-existed.
364
365   char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
366   sprintf(newDir, "%s/%s", newContainer, dateDirName);
367
368   log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
369   int renameret = rename(t, newDir);
370   if (renameret == 0)
371   {
372     // Success. Test for remove old dir containter
373     char* oldTitleDir = new char[k+1];
374     memcpy(oldTitleDir, t, k);
375     oldTitleDir[k] = '\0';
376     log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
377     rmdir(oldTitleDir); // can't do anything about a fail result at this point.
378     delete[] oldTitleDir;
379
380     ::Recordings.Update();
381     js["Result"] = true;
382   }
383   else
384   {
385     log->log("JSONServer", Log::ERR, "Rename failed");
386     js["Result"] = false;
387     js["Error"] = "Move failed";
388   }
389
390   delete[] dateDirName;
391   delete[] titleDirName;
392   delete[] newContainer;
393   delete[] newDir;
394
395   return true;
396 }
397
398 bool jsonserver_channellist(Json::Value& js)
399 {
400   Log* log = Log::getInstance();
401   log->log("JSONServer", Log::DEBUG, "channellist");
402
403   Json::Value jschannels;
404   
405   int type;
406   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
407   {
408     if (!channel->GroupSep())
409     {
410       log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
411
412       if (channel->Vpid()) type = 1;
413       else if (channel->Apid(0)) type = 2;
414       else continue;
415
416       Json::Value oneChannel;
417       oneChannel["Number"] = channel->Number();
418       oneChannel["Type"] = type;
419       oneChannel["Name"] = channel->Name();
420 #if VDRVERSNUM < 10703
421       oneChannel["VType"] = 2;
422 #else
423       oneChannel["VType"] = channel->Vtype();
424 #endif
425       jschannels.append(oneChannel);    
426     }
427   }
428   js["Channels"] = jschannels;
429   
430   return true;
431 }
432
433 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
434 {
435   Log* log = Log::getInstance();
436   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
437
438   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);  
439   char sStartTime[15];      int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);  
440   char sDuration[15];       int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);  
441
442   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
443   {
444     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
445     js["Result"] = false;
446     js["Error"] = "Bad request parameters";
447     return true;
448   }
449
450   int channelNumber = atoi(sChannelNumber);
451   int startTime = atoi(sStartTime); 
452   int duration = atoi(sDuration); 
453
454   cChannel* channel = NULL;
455   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
456   {
457     if (channel->GroupSep()) continue;
458     if (channel->Number() == channelNumber) break;
459   }
460
461   if (!channel)
462   {
463     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
464     js["Result"] = false;
465     js["Error"] = "Could not find channel";
466     return true;
467   }
468
469   cSchedulesLock MutexLock;
470   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
471   if (!Schedules)
472   {
473     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
474     js["Result"] = false;
475     js["Error"] = "Internal schedules error (1)";
476     return true;
477   }
478   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
479   if (!Schedule)     
480   {
481     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
482     js["Result"] = false;
483     js["Error"] = "Internal schedules error (2)";
484     return true;
485   }
486     
487   Json::Value jsevents;
488
489   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
490   {
491     //in the past filter
492     if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
493    //start time filter
494     if ((event->StartTime() + event->Duration()) <= startTime) continue;
495     //duration filter
496     if (event->StartTime() >= (startTime + duration)) continue;
497
498     Json::Value oneEvent;
499     oneEvent["ID"] = event->EventID();
500     oneEvent["Time"] = (Json::UInt)event->StartTime();
501     oneEvent["Duration"] = event->Duration();
502     oneEvent["Title"] = event->Title() ? event->Title() : "";
503     oneEvent["Description"] = event->Description() ? event->Description() : "";
504     jsevents.append(oneEvent);
505   }
506
507   js["Events"] = jsevents;
508   return true;
509 }
510
511 bool jsonserver_timerlist(Json::Value& js)
512 {
513   Log* log = Log::getInstance();
514   log->log("JSONServer", Log::DEBUG, "timerlist");
515
516   Json::Value jstimers;
517   
518   cTimer *timer;
519   int numTimers = Timers.Count();
520
521   for (int i = 0; i < numTimers; i++)
522   {
523     timer = Timers.Get(i);
524     Json::Value oneTimer;
525     oneTimer["Active"] = timer->HasFlags(tfActive);
526     oneTimer["Recording"] = timer->Recording();
527     oneTimer["Pending"] = timer->Pending();
528     oneTimer["Priority"] = timer->Priority();
529     oneTimer["Lifetime"] = timer->Lifetime();
530     oneTimer["ChannelNumber"] = timer->Channel()->Number();
531     oneTimer["StartTime"] = (int)timer->StartTime();
532     oneTimer["StopTime"] = (int)timer->StopTime();
533     oneTimer["Day"] = (int)timer->Day();
534     oneTimer["WeekDays"] = timer->WeekDays();
535     oneTimer["Name"] = timer->File();
536     jstimers.append(oneTimer);
537   }
538   
539   js["Timers"] = jstimers;
540   return true;
541 }
542
543 bool jsonserver_timerdel(Json::Value& js, const char* postData)
544 {
545   Log* log = Log::getInstance();
546   log->log("JSONServer", Log::DEBUG, "timerdel");
547
548   char sdelChannel[15];   int mgv1 = mg_get_var(postData, strlen(postData), "delchannel", sdelChannel, 15);  
549   char sdelWeekdays[15];  int mgv2 = mg_get_var(postData, strlen(postData), "delweekdays", sdelWeekdays, 15);  
550   char sdelDay[15];       int mgv3 = mg_get_var(postData, strlen(postData), "delday", sdelDay, 15);  
551   char sdelStart[15];     int mgv4 = mg_get_var(postData, strlen(postData), "delstart", sdelStart, 15);  
552   char sdelStop[15];      int mgv5 = mg_get_var(postData, strlen(postData), "delstop", sdelStop, 15);  
553
554   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
555   {
556     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
557     js["Result"] = false;
558     js["Error"] = "Bad request parameters";
559     return true;
560   }
561
562   int delChannel = atoi(sdelChannel); 
563   int delWeekdays = atoi(sdelWeekdays); 
564   int delDay = atoi(sdelDay); 
565   int delStart = atoi(sdelStart); 
566   int delStop = atoi(sdelStop); 
567
568   cTimer* ti = NULL;
569   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
570   {
571     if  ( (ti->Channel()->Number() == delChannel)
572      &&   ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
573      &&   (ti->StartTime() == delStart)
574      &&   (ti->StopTime() == delStop) )
575        break;
576   }
577   
578   if (!ti)
579   {
580     log->log("JSONServer", Log::ERR, "Could not find timer");
581     js["Result"] = false;
582     js["Error"] = "Could not find timer";
583     return true;
584   }
585
586   if (Timers.BeingEdited())
587   {
588     log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
589     js["Result"] = false;
590     js["Error"] = "Timers being edited at VDR";
591     return true; 
592   }
593   
594   if (ti->Recording())
595   {
596     log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
597     js["Result"] = false;
598     js["Error"] = "Timer is running";
599     return true;
600   }
601   
602   Timers.Del(ti);
603   Timers.SetModified();
604   js["Result"] = true;
605     
606   return true;
607 }
608
609 bool jsonserver_timerset(Json::Value& js, const char* postData)
610 {
611   Log* log = Log::getInstance();
612   log->log("JSONServer", Log::DEBUG, "timerset");
613
614   char sTimerString[1024];   int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);  
615
616   if (mgv1 == -1)
617   {
618     log->log("JSONServer", Log::ERR, "Could not get timerstring");
619     js["Result"] = false;
620     js["Error"] = "Bad request parameters";
621     return true;
622   }
623
624   log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
625   cTimer *timer = new cTimer;
626   if (!timer->Parse(sTimerString))
627   {
628     delete timer;
629     js["Result"] = false;
630     js["Error"] = "Failed to parse timer request details";
631     return true;
632   }
633
634   cTimer *t = Timers.GetTimer(timer);
635   if (t)
636   {
637     delete timer;
638     js["Result"] = false;
639     js["Error"] = "Timer already exists";
640     return true;
641   }
642
643   Timers.Add(timer);
644   Timers.SetModified();
645   js["Result"] = true;
646   return true;
647 }
648