]> git.vomp.tv Git - jsonserver.git/blob - handler.c
Return all channels for channel list, remove unnecessary data
[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       postData[contentLengthI] = '\0';
64     }
65   }
66
67   Json::Value js;
68   bool success = false;
69
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);
80
81   if (!success) return 0; // the specific handler failed badly
82
83   // Now js will be filled
84
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());
90   return 1;
91
92   
93 /*
94   else if (event == MG_EVENT_LOG)
95   {
96     if (request_info->status_code == 400) // bad request
97     {
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++)
105       {
106         log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
107       }
108     }
109     else
110     {
111       log->log("Mongoose", Log::DEBUG, request_info->log_message);
112       log->log("Mongoose", Log::DEBUG, request_info->uri);
113     }
114     return (void*)1;
115   }
116   
117   // other events not handled:
118   // MG_HTTP_ERROR, MG_INIT_SSL
119   // Let mongoose do something with those
120
121   return NULL;
122
123 */
124   
125 }
126
127 bool jsonserver_reclist(Json::Value& js)
128 {
129   Log* log = Log::getInstance();
130   log->log("JSONServer", Log::DEBUG, "reclist");
131
132   int FreeMB;
133   int Percent = VideoDiskSpace(&FreeMB);
134   int Total = (FreeMB / (100 - Percent)) * 100;
135         
136   js["MBFree"] = FreeMB;
137   js["Percent"] = Percent;
138   js["Total"] = Total;
139   
140   Json::Value jsrecordings;
141   cRecordings Recordings;
142   Recordings.Load();
143   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
144   {
145     Json::Value oneRec;
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);
153   }
154   js["Recordings"] = jsrecordings;
155   
156   return true;
157 }
158
159 bool jsonserver_recinfo(Json::Value& js, const char* postData)
160 {
161   Log* log = Log::getInstance();
162   log->log("JSONServer", Log::DEBUG, "recinfo");
163
164   char reqfilename[1000];
165   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
166   if (mgv1 == -1)
167   {
168     log->log("JSONServer", Log::ERR, "Could not decode filename");
169     js["Result"] = false;
170     js["Error"] = "Could not decode filename";
171     return true;
172   }
173
174   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
175   
176   cRecordings Recordings;
177   Recordings.Load(); // probably have to do this
178   cRecording *recording = Recordings.GetByName(reqfilename);
179
180   if (!recording)
181   {
182     log->log("JSONServer", Log::ERR, "recinfo found no recording");
183     js["Result"] = false;
184     return true;
185   }
186
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();
194
195   js["ResumePoint"] = 0;
196   cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
197   if (ResumeFile.Read() >= 0) js["ResumePoint"] = ResumeFile.Read();
198
199   js["CurrentlyRecordingStart"] = 0;
200   js["CurrentlyRecordingStop"] = 0;
201   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
202   if (rc)
203   {
204     js["CurrentlyRecordingStart"] = (Json::UInt)rc->Timer()->StartTime();
205     js["CurrentlyRecordingStop"] = (Json::UInt)rc->Timer()->StopTime();
206   }
207
208   const cRecordingInfo *info = recording->Info();
209   if (info)
210   {
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;
215
216     const cComponents* components = info->Components();
217     if (!components)
218     {
219       js["Components"] = Json::Value::null;
220     }
221     else
222     {
223       Json::Value jscomponents;
224
225       tComponent* component;
226       for (int i = 0; i < components->NumComponents(); i++)
227       {
228         component = components->Component(i);
229
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);
236       }
237
238       js["Components"] = jscomponents;
239     }
240   }
241
242   js["Result"] = true;
243   return true;
244 }
245
246 bool jsonserver_recstop(Json::Value& js, const char* postData)
247 {
248   Log* log = Log::getInstance();
249   log->log("JSONServer", Log::DEBUG, "recstop");
250   
251   char reqfilename[1000];
252   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
253   if (mgv1 == -1)
254   {
255     log->log("JSONServer", Log::ERR, "Could not decode filename");
256     js["Result"] = false;
257     js["Error"] = "Could not decode filename";
258     return true;
259   }
260   
261   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
262   
263   cRecordings Recordings;
264   Recordings.Load(); // probably have to do this
265   cRecording *recording = Recordings.GetByName(reqfilename);
266   
267   if (!recording)
268   {
269     log->log("JSONServer", Log::ERR, "recstop found no recording");
270     js["Result"] = false;
271     return true;
272   }
273
274   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
275   if (!rc)
276   {
277     log->log("JSONServer", Log::ERR, "recstop - not currently recording");
278     js["Result"] = false;
279     return true;
280   }
281
282   if (Timers.BeingEdited())
283   {
284     log->log("JSONServer", Log::ERR, "recstop - timers being edited elsewhere");
285     js["Result"] = false;
286     return true;
287   }
288
289   cTimer* timer = rc->Timer();
290   if (!timer)
291   {
292     log->log("JSONServer", Log::ERR, "recstop - timer not found");
293     js["Result"] = false;
294     return true;
295   }
296   
297   timer->ClrFlags(tfActive);
298   Timers.SetModified();
299   
300   js["Result"] = true;
301   return true;
302 }  
303   
304 bool jsonserver_recdel(Json::Value& js, const char* postData)
305 {
306   Log* log = Log::getInstance();
307   log->log("JSONServer", Log::DEBUG, "recdel");
308
309   char reqfilename[1000];
310   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
311   if (mgv1 == -1)
312   {
313     log->log("JSONServer", Log::ERR, "Could not decode filename");
314     js["Result"] = false;
315     js["Error"] = "Could not decode filename";
316     return true;
317   }
318
319   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
320   
321   cRecordings Recordings;
322   Recordings.Load(); // probably have to do this
323   cRecording *recording = Recordings.GetByName(reqfilename);
324
325   if (!recording)
326   {
327     js["Result"] = false;
328     js["Error"] = "Could not find recording to delete";
329     return true;
330   }
331
332   log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
333   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
334   if (rc)
335   {
336     js["Result"] = false;
337     js["Error"] = "This recording is still recording.. ho ho";
338     return true;
339   }
340
341   if (recording->Delete())
342   {
343     ::Recordings.DelByName(recording->FileName());
344     js["Result"] = true;
345   }
346   else
347   {
348     js["Result"] = false;
349     js["Error"] = "Failed to delete recording";
350   }
351
352   return true;
353 }
354
355 bool jsonserver_recmove(Json::Value& js, const char* postData)
356 {
357   Log* log = Log::getInstance();
358   log->log("JSONServer", Log::DEBUG, "recmove");
359
360   char* fileNameToMove = NULL;
361   char* requestedNewPath = NULL;
362   char* dateDirName = NULL;
363   char* titleDirName = NULL;
364   char* folderName = NULL;
365   char* newContainer = NULL;
366   char* newDir = NULL;
367   
368   try
369   {
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);
375
376     if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToMove) || !strlen(requestedNewPath))
377     {
378       log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
379       throw 1;
380     }
381
382     cRecordings Recordings;
383     Recordings.Load(); // probably have to do this
384     cRecording* recordingObj = Recordings.GetByName(fileNameToMove);
385     if (!recordingObj) throw 2;
386     
387     cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
388     if (rc) throw 3;
389
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);
393
394     const char* t = recordingObj->FileName();
395
396     int k, j, m;
397
398     // Find the datedirname
399     for(k = strlen(t) - 1; k >= 0; k--)
400     {
401       if (t[k] == '/')
402       {
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]);
406         break;
407       }
408     }
409
410     // Find the titledirname
411
412     for(j = k-1; j >= 0; j--)
413     {
414       if (t[j] == '/')
415       {
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';
420         break;
421       }
422     }
423
424     // Find the foldername
425
426     log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, strlen(VideoDirectory));
427     if (j > strlen(VideoDirectory)) // Rec is in a subfolder now
428     {
429       for(m = j-1; m >= 0; m--)
430       {
431         if (t[m] == '/')
432         {
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';
437           break;
438         }
439       }
440     }
441
442     ExchangeChars(requestedNewPath, true);
443
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);
449
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);
454     struct stat dstat;
455     int statret = stat(newContainer, &dstat);
456     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
457     {
458       log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
459       int mkdirret = mkdir(newContainer, 0755);
460       if (mkdirret != 0) throw 4;
461     }
462     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
463     {
464       // Something exists but it's not a dir
465       throw 5;
466     }
467
468     // New path now created or was there already
469
470     sprintf(newContainer, "%s%s%s", VideoDirectory, requestedNewPath, titleDirName);
471     log->log("JSONServer", Log::DEBUG, "%s", newContainer);
472
473     statret = stat(newContainer, &dstat);
474     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
475     {
476       log->log("JSONServer", Log::DEBUG, "new dir does not exist (2)");
477       int mkdirret = mkdir(newContainer, 0755);
478       if (mkdirret != 0) throw 6;
479     }
480     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
481     {
482       // Something exists but it's not a dir
483       throw 7;
484     }
485
486     // Ok, the directory container has been made, or it pre-existed.
487
488     newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
489     sprintf(newDir, "%s/%s", newContainer, dateDirName);
490
491     log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
492     if (rename(t, newDir) != 0) throw 8;
493     
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;
501
502     // Test for remove old foldername
503     if (folderName)
504     {
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);
509       /*
510       DESCRIPTION
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
514       */
515       rmdir(tempOldFolderName); // can't do anything about a fail result at this point.
516       delete[] tempOldFolderName;
517     }
518
519     ::Recordings.Update();
520     js["Result"] = true;
521     js["NewRecordingFileName"] = newDir;
522   }
523   catch (int e)
524   {
525     js["Result"] = false;
526     if (e == 1)
527     {
528       log->log("JSONServer", Log::ERR, "Bad parameters");
529       js["Error"] = "Bad request parameters";
530     }
531     else if (e == 2)
532     {
533       log->log("JSONServer", Log::ERR, "Could not find recording to move");
534       js["Error"] = "Bad filename";
535     }
536     else if (e == 3)
537     {
538       log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
539       js["Error"] = "Cannot move recording in progress";
540     }
541     else if (e == 4)
542     {
543       log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
544       js["Error"] = "Failed to create new directory (1)";
545     }
546     else if (e == 5)
547     {
548       log->log("JSONServer", Log::ERR, "Something already exists? (1)");
549       js["Error"] = "Something already exists at the new path (1)";
550     }
551     else if (e == 6)
552     {
553       log->log("JSONServer", Log::ERR, "Failed to make new dir (2)");
554       js["Error"] = "Failed to create new directory (2)";
555     }
556     else if (e == 7)
557     {
558       log->log("JSONServer", Log::ERR, "Something already exists?");
559       js["Error"] = "Something already exists at the new path";
560     }
561     else if (e == 8)
562     {
563       log->log("JSONServer", Log::ERR, "Rename failed");
564       js["Error"] = "Move failed";
565     }
566   }
567
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;
575
576   return true;
577 }
578
579 bool jsonserver_channellist(Json::Value& js)
580 {
581   Log* log = Log::getInstance();
582   log->log("JSONServer", Log::DEBUG, "channellist");
583
584   Json::Value jschannels;
585   
586   int type;
587   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
588   {
589     if (!channel->GroupSep())
590     {
591 //      log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
592
593 //      if (channel->Vpid()) type = 1;
594 //      else if (channel->Apid(0)) type = 2;
595 //      else continue;
596
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;
603 //#else
604 //      oneChannel["VType"] = channel->Vtype();
605 //#endif
606       jschannels.append(oneChannel);    
607     }
608   }
609   js["Channels"] = jschannels;
610   
611   return true;
612 }
613
614 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
615 {
616   Log* log = Log::getInstance();
617   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
618
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);  
622
623   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
624   {
625     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
626     js["Result"] = false;
627     js["Error"] = "Bad request parameters";
628     return true;
629   }
630
631   int channelNumber = atoi(sChannelNumber);
632   int startTime = atoi(sStartTime); 
633   int duration = atoi(sDuration); 
634
635   cChannel* channel = NULL;
636   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
637   {
638     if (channel->GroupSep()) continue;
639     if (channel->Number() == channelNumber) break;
640   }
641
642   if (!channel)
643   {
644     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
645     js["Result"] = false;
646     js["Error"] = "Could not find channel";
647     return true;
648   }
649
650   cSchedulesLock MutexLock;
651   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
652   if (!Schedules)
653   {
654     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
655     js["Result"] = false;
656     js["Error"] = "Internal schedules error (1)";
657     return true;
658   }
659   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
660   if (!Schedule)     
661   {
662     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
663     js["Result"] = false;
664     js["Error"] = "Internal schedules error (2)";
665     return true;
666   }
667     
668   Json::Value jsevents;
669
670   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
671   {
672     //in the past filter
673     if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
674    //start time filter
675     if ((event->StartTime() + event->Duration()) <= startTime) continue;
676     //duration filter
677     if (event->StartTime() >= (startTime + duration)) continue;
678
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["ShortText"] = event->ShortText() ? event->ShortText() : "";
685     //oneEvent["Description"] = event->Description() ? event->Description() : "";
686     jsevents.append(oneEvent);
687   }
688
689   js["Result"] = true;
690   js["Events"] = jsevents;
691   return true;
692 }
693
694 bool jsonserver_timerlist(Json::Value& js)
695 {
696   Log* log = Log::getInstance();
697   log->log("JSONServer", Log::DEBUG, "timerlist");
698
699   Json::Value jstimers;
700   
701   cTimer *timer;
702   int numTimers = Timers.Count();
703
704   for (int i = 0; i < numTimers; i++)
705   {
706     timer = Timers.Get(i);
707     Json::Value oneTimer;
708     oneTimer["Active"] = timer->HasFlags(tfActive);
709     oneTimer["Recording"] = timer->Recording();
710     oneTimer["Pending"] = timer->Pending();
711     oneTimer["Priority"] = timer->Priority();
712     oneTimer["Lifetime"] = timer->Lifetime();
713     oneTimer["ChannelNumber"] = timer->Channel()->Number();
714     oneTimer["StartTime"] = (int)timer->StartTime();
715     oneTimer["StopTime"] = (int)timer->StopTime();
716     oneTimer["Day"] = (int)timer->Day();
717     oneTimer["WeekDays"] = timer->WeekDays();
718     oneTimer["Name"] = timer->File();
719     jstimers.append(oneTimer);
720   }
721   
722   js["Timers"] = jstimers;
723   return true;
724 }
725
726 bool jsonserver_timerdel(Json::Value& js, const char* postData)
727 {
728   Log* log = Log::getInstance();
729   log->log("JSONServer", Log::DEBUG, "timerdel");
730
731   char sdelChannel[15];   int mgv1 = mg_get_var(postData, strlen(postData), "delchannel", sdelChannel, 15);  
732   char sdelWeekdays[15];  int mgv2 = mg_get_var(postData, strlen(postData), "delweekdays", sdelWeekdays, 15);  
733   char sdelDay[15];       int mgv3 = mg_get_var(postData, strlen(postData), "delday", sdelDay, 15);  
734   char sdelStart[15];     int mgv4 = mg_get_var(postData, strlen(postData), "delstart", sdelStart, 15);  
735   char sdelStop[15];      int mgv5 = mg_get_var(postData, strlen(postData), "delstop", sdelStop, 15);  
736
737   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
738   {
739     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
740     js["Result"] = false;
741     js["Error"] = "Bad request parameters";
742     return true;
743   }
744
745   int delChannel = atoi(sdelChannel); 
746   int delWeekdays = atoi(sdelWeekdays); 
747   int delDay = atoi(sdelDay); 
748   int delStart = atoi(sdelStart); 
749   int delStop = atoi(sdelStop); 
750
751   cTimer* ti = NULL;
752   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
753   {
754     if  ( (ti->Channel()->Number() == delChannel)
755      &&   ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
756      &&   (ti->StartTime() == delStart)
757      &&   (ti->StopTime() == delStop) )
758        break;
759   }
760   
761   if (!ti)
762   {
763     log->log("JSONServer", Log::ERR, "Could not find timer");
764     js["Result"] = false;
765     js["Error"] = "Could not find timer";
766     return true;
767   }
768
769   if (Timers.BeingEdited())
770   {
771     log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
772     js["Result"] = false;
773     js["Error"] = "Timers being edited at VDR";
774     return true; 
775   }
776   
777   if (ti->Recording())
778   {
779     log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
780     js["Result"] = false;
781     js["Error"] = "Timer is running";
782     return true;
783   }
784   
785   Timers.Del(ti);
786   Timers.SetModified();
787   js["Result"] = true;
788     
789   return true;
790 }
791
792 bool jsonserver_timerset(Json::Value& js, const char* postData)
793 {
794   Log* log = Log::getInstance();
795   log->log("JSONServer", Log::DEBUG, "timerset");
796
797   char sTimerString[1024];   int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);  
798
799   if (mgv1 == -1)
800   {
801     log->log("JSONServer", Log::ERR, "Could not get timerstring");
802     js["Result"] = false;
803     js["Error"] = "Bad request parameters";
804     return true;
805   }
806
807   log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
808   cTimer *timer = new cTimer;
809   if (!timer->Parse(sTimerString))
810   {
811     delete timer;
812     js["Result"] = false;
813     js["Error"] = "Failed to parse timer request details";
814     return true;
815   }
816
817   cTimer *t = Timers.GetTimer(timer);
818   if (t)
819   {
820     delete timer;
821     js["Result"] = false;
822     js["Error"] = "Timer already exists";
823     return true;
824   }
825
826   Timers.Add(timer);
827   Timers.SetModified();
828   js["Result"] = true;
829   return true;
830 }
831