]> git.vomp.tv Git - jsonserver.git/blob - handler.c
Add gettime and diskstat calls
[jsonserver.git] / handler.c
1 #include "handler.h"
2
3 #include <string.h>
4 #include <stdlib.h>
5 #include <sys/time.h>
6 #include <jsoncpp/json/json.h>
7 #include <string>
8
9 #include <vdr/videodir.h>
10 #include <vdr/recording.h>
11 #include <vdr/menu.h>
12 #include <vdr/timers.h>
13
14 #include "log.h"
15
16 int jsonserver_request_handler(struct mg_connection *conn)
17 {
18   Log* log = Log::getInstance();
19   const struct mg_request_info *request_info = mg_get_request_info(conn);
20   
21   if (strcmp(request_info->uri, "/jsonserver")) return 0; // not for us
22
23   char wvrequest[20];
24   int wvrl = mg_get_var(request_info->query_string, strlen(request_info->query_string), "req", wvrequest, 20);
25   if (wvrl == -1)
26   {
27     log->log("JSONServer", Log::ERR, "Could not decode req");
28     return 0;
29   }
30
31 /*
32   if (!strcmp(request_info->request_method, "OPTIONS"))
33   {
34     mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
35     mg_printf(conn, "%s", "Access-Control-Allow-Origin: *\r\n");
36     mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
37     return (void*)1;
38   }
39 */
40
41   // Get POST data
42   char postData[10000];
43   postData[0] = '\0';
44   if (!strcmp(request_info->request_method, "POST"))
45   {
46     const char* contentLength = mg_get_header(conn, "Content-Length");
47     int contentLengthI = atoi(contentLength);
48     log->log("JSONServer", Log::DEBUG, "POST data content length: %i", contentLengthI);
49     if (contentLengthI > 10000)
50     {
51       log->log("JSONServer", Log::DEBUG, "Length > 10000, rejecting");
52       return 0;
53     }
54
55     if (contentLengthI > 0)
56     {
57       // FIXME - assume for now that all post data will be small enough to have arrived immediately
58       int bytesRead = mg_read(conn, postData, contentLengthI);
59       if (bytesRead != contentLengthI)
60       {
61         log->log("JSONServer", Log::DEBUG, "Could not read up to contentLength");
62         return 0;
63       }
64       postData[contentLengthI] = '\0';
65     }
66   }
67
68   Json::Value js;
69   bool success = false;
70
71   if      (!strcmp(wvrequest, "gettime")) success = jsonserver_gettime(js);
72   else if (!strcmp(wvrequest, "diskstats")) success = jsonserver_diskstats(js);
73   else if (!strcmp(wvrequest, "reclist")) success = jsonserver_reclist(js);
74   else if (!strcmp(wvrequest, "recinfo")) success = jsonserver_recinfo(js, postData);
75   else if (!strcmp(wvrequest, "recdel")) success = jsonserver_recdel(js, postData);
76   else if (!strcmp(wvrequest, "recmove")) success = jsonserver_recmove(js, postData);
77   else if (!strcmp(wvrequest, "recstop")) success = jsonserver_recstop(js, postData);
78   else if (!strcmp(wvrequest, "channellist")) success = jsonserver_channellist(js);
79   else if (!strcmp(wvrequest, "channelschedule")) success = jsonserver_channelschedule(js, postData);
80   else if (!strcmp(wvrequest, "getscheduleevent")) success = jsonserver_getscheduleevent(js, postData);
81   else if (!strcmp(wvrequest, "timerlist")) success = jsonserver_timerlist(js);
82   else if (!strcmp(wvrequest, "timerdel")) success = jsonserver_timerdel(js, postData);
83   else if (!strcmp(wvrequest, "timerset")) success = jsonserver_timerset(js, postData);
84
85   if (!success) return 0; // the specific handler failed badly
86
87   // Now js will be filled
88
89   Json::StyledWriter sw;
90   std::string jsonout = sw.write(js);
91   mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n");
92   mg_printf(conn, "%s", "Content-Type: text/plain\r\n\r\n");
93   mg_write(conn, jsonout.c_str(), jsonout.length());
94   return 1;
95
96   
97 /*
98   else if (event == MG_EVENT_LOG)
99   {
100     if (request_info->status_code == 400) // bad request
101     {
102       log->log("Mongoose", Log::DEBUG, "400 BAD REQUEST:");
103       log->log("Mongoose", Log::DEBUG, request_info->request_method);
104       log->log("Mongoose", Log::DEBUG, request_info->uri);
105       log->log("Mongoose", Log::DEBUG, request_info->http_version);
106       log->log("Mongoose", Log::DEBUG, request_info->query_string);
107       log->log("Mongoose", Log::DEBUG, request_info->log_message);
108       for (int i = 0; i < request_info->num_headers; i++)
109       {
110         log->log("Mongoose", Log::DEBUG, "%s: %s", request_info->http_headers[i].name, request_info->http_headers[i].value);
111       }
112     }
113     else
114     {
115       log->log("Mongoose", Log::DEBUG, request_info->log_message);
116       log->log("Mongoose", Log::DEBUG, request_info->uri);
117     }
118     return (void*)1;
119   }
120   
121   // other events not handled:
122   // MG_HTTP_ERROR, MG_INIT_SSL
123   // Let mongoose do something with those
124
125   return NULL;
126
127 */
128   
129 }
130
131 bool jsonserver_gettime(Json::Value& js)
132 {
133   Log* log = Log::getInstance();
134   log->log("JSONServer", Log::DEBUG, "gettime");
135
136   struct timeval tv;
137   gettimeofday(&tv, NULL);
138   
139   js["Time"] = (Json::UInt64)tv.tv_sec;
140   js["MTime"] = (Json::UInt)(tv.tv_usec/1000);
141   js["Result"] = true;
142   return true;
143 }
144
145 bool jsonserver_diskstats(Json::Value& js)
146 {
147   Log* log = Log::getInstance();
148   log->log("JSONServer", Log::DEBUG, "diskstats");
149   
150   int FreeMB;
151   int UsedMB;
152   int Percent = VideoDiskSpace(&FreeMB, &UsedMB);
153   
154   js["FreeMiB"] = FreeMB;
155   js["UsedMiB"] = UsedMB;
156   js["Percent"] = Percent;
157   
158   js["Result"] = true;
159   return true;
160 }
161
162 bool jsonserver_reclist(Json::Value& js)
163 {
164   Log* log = Log::getInstance();
165   log->log("JSONServer", Log::DEBUG, "reclist");
166
167   Json::Value jsrecordings;
168   cRecordings Recordings;
169   Recordings.Load();
170   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
171   {
172     Json::Value oneRec;
173     oneRec["StartTime"] = (Json::UInt)recording->Start();
174     oneRec["Length"] = (Json::UInt)recording->LengthInSeconds();
175     oneRec["IsNew"] = recording->IsNew();
176     oneRec["Name"] = recording->Name();
177     oneRec["Filename"] = recording->FileName();
178     oneRec["FileSizeMB"] = recording->FileSizeMB();
179     jsrecordings.append(oneRec);
180   }
181   js["Recordings"] = jsrecordings;
182   
183   return true;
184 }
185
186 bool jsonserver_recinfo(Json::Value& js, const char* postData)
187 {
188   Log* log = Log::getInstance();
189   log->log("JSONServer", Log::DEBUG, "recinfo");
190
191   char reqfilename[1000];
192   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
193   if (mgv1 == -1)
194   {
195     log->log("JSONServer", Log::ERR, "Could not decode filename");
196     js["Result"] = false;
197     js["Error"] = "Could not decode filename";
198     return true;
199   }
200
201   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
202   
203   cRecordings Recordings;
204   Recordings.Load(); // probably have to do this
205   cRecording *recording = Recordings.GetByName(reqfilename);
206
207   if (!recording)
208   {
209     log->log("JSONServer", Log::ERR, "recinfo found no recording");
210     js["Result"] = false;
211     return true;
212   }
213
214   js["IsNew"] = recording->IsNew();
215   js["LengthInSeconds"] = recording->LengthInSeconds();
216   js["FileSizeMB"] = recording->FileSizeMB();
217   js["Name"] = recording->Name() ? recording->Name() : Json::Value::null;
218   js["Priority"] = recording->Priority();
219   js["LifeTime"] = recording->Lifetime();
220   js["Start"] = (Json::UInt)recording->Start();
221
222   js["ResumePoint"] = 0;
223   cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording());
224   if (ResumeFile.Read() >= 0) js["ResumePoint"] = ResumeFile.Read();
225
226   js["CurrentlyRecordingStart"] = 0;
227   js["CurrentlyRecordingStop"] = 0;
228   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
229   if (rc)
230   {
231     js["CurrentlyRecordingStart"] = (Json::UInt)rc->Timer()->StartTime();
232     js["CurrentlyRecordingStop"] = (Json::UInt)rc->Timer()->StopTime();
233   }
234
235   const cRecordingInfo *info = recording->Info();
236   if (info)
237   {
238     js["ChannelName"] = info->ChannelName() ? info->ChannelName() : Json::Value::null;
239     js["Title"] = info->Title() ? info->Title() : Json::Value::null;
240     js["ShortText"] = info->ShortText() ? info->ShortText() : Json::Value::null;
241     js["Description"] = info->Description() ? info->Description() : Json::Value::null;
242
243     const cComponents* components = info->Components();
244     if (!components)
245     {
246       js["Components"] = Json::Value::null;
247     }
248     else
249     {
250       Json::Value jscomponents;
251
252       tComponent* component;
253       for (int i = 0; i < components->NumComponents(); i++)
254       {
255         component = components->Component(i);
256
257         Json::Value oneComponent;
258         oneComponent["Stream"] = component->stream;
259         oneComponent["Type"] = component->type;
260         oneComponent["Language"] = component->language ? component->language : Json::Value::null;
261         oneComponent["Description"] = component->description ? component->description : Json::Value::null;
262         jscomponents.append(oneComponent);
263       }
264
265       js["Components"] = jscomponents;
266     }
267   }
268
269   js["Result"] = true;
270   return true;
271 }
272
273 bool jsonserver_recstop(Json::Value& js, const char* postData)
274 {
275   Log* log = Log::getInstance();
276   log->log("JSONServer", Log::DEBUG, "recstop");
277   
278   char reqfilename[1000];
279   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
280   if (mgv1 == -1)
281   {
282     log->log("JSONServer", Log::ERR, "Could not decode filename");
283     js["Result"] = false;
284     js["Error"] = "Could not decode filename";
285     return true;
286   }
287   
288   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
289   
290   cRecordings Recordings;
291   Recordings.Load(); // probably have to do this
292   cRecording *recording = Recordings.GetByName(reqfilename);
293   
294   if (!recording)
295   {
296     log->log("JSONServer", Log::ERR, "recstop found no recording");
297     js["Result"] = false;
298     return true;
299   }
300
301   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
302   if (!rc)
303   {
304     log->log("JSONServer", Log::ERR, "recstop - not currently recording");
305     js["Result"] = false;
306     return true;
307   }
308
309   if (Timers.BeingEdited())
310   {
311     log->log("JSONServer", Log::ERR, "recstop - timers being edited elsewhere");
312     js["Result"] = false;
313     return true;
314   }
315
316   cTimer* timer = rc->Timer();
317   if (!timer)
318   {
319     log->log("JSONServer", Log::ERR, "recstop - timer not found");
320     js["Result"] = false;
321     return true;
322   }
323   
324   timer->ClrFlags(tfActive);
325   Timers.SetModified();
326   
327   js["Result"] = true;
328   return true;
329 }  
330   
331 bool jsonserver_recdel(Json::Value& js, const char* postData)
332 {
333   Log* log = Log::getInstance();
334   log->log("JSONServer", Log::DEBUG, "recdel");
335
336   char reqfilename[1000];
337   int mgv1 = mg_get_var(postData, strlen(postData), "filename", reqfilename, 1000);
338   if (mgv1 == -1)
339   {
340     log->log("JSONServer", Log::ERR, "Could not decode filename");
341     js["Result"] = false;
342     js["Error"] = "Could not decode filename";
343     return true;
344   }
345
346   log->log("JSONServer", Log::DEBUG, "%s", reqfilename);
347   
348   cRecordings Recordings;
349   Recordings.Load(); // probably have to do this
350   cRecording *recording = Recordings.GetByName(reqfilename);
351
352   if (!recording)
353   {
354     js["Result"] = false;
355     js["Error"] = "Could not find recording to delete";
356     return true;
357   }
358
359   log->log("JSONServer", Log::DEBUG, "Deleting recording: %s", recording->Name());
360   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
361   if (rc)
362   {
363     js["Result"] = false;
364     js["Error"] = "This recording is still recording.. ho ho";
365     return true;
366   }
367
368   if (recording->Delete())
369   {
370     ::Recordings.DelByName(recording->FileName());
371     js["Result"] = true;
372   }
373   else
374   {
375     js["Result"] = false;
376     js["Error"] = "Failed to delete recording";
377   }
378
379   return true;
380 }
381
382 bool jsonserver_recmove(Json::Value& js, const char* postData)
383 {
384   Log* log = Log::getInstance();
385   log->log("JSONServer", Log::DEBUG, "recmove");
386
387   char* fileNameToMove = NULL;
388   char* requestedNewPath = NULL;
389   char* dateDirName = NULL;
390   char* titleDirName = NULL;
391   char* folderName = NULL;
392   char* newContainer = NULL;
393   char* newDir = NULL;
394   
395   try
396   {
397     int postDataLen = strlen(postData)+1;
398     fileNameToMove = new char[postDataLen];
399     int mgv1 = mg_get_var(postData, postDataLen-1, "filename", fileNameToMove, postDataLen);
400     requestedNewPath = new char[postDataLen];
401     int mgv2 = mg_get_var(postData, postDataLen-1, "newpath", requestedNewPath, postDataLen);
402
403     if ((mgv1 == -1) || (mgv2 == -1) || !strlen(fileNameToMove) || !strlen(requestedNewPath))
404     {
405       log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
406       throw 1;
407     }
408
409     cRecordings Recordings;
410     Recordings.Load(); // probably have to do this
411     cRecording* recordingObj = Recordings.GetByName(fileNameToMove);
412     if (!recordingObj) throw 2;
413     
414     cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
415     if (rc) throw 3;
416
417     log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->Name());
418     log->log("JSONServer", Log::DEBUG, "moving recording: %s", recordingObj->FileName());
419     log->log("JSONServer", Log::DEBUG, "to: %s", requestedNewPath);
420
421     const char* t = recordingObj->FileName();
422
423     int k, j, m;
424
425     // Find the datedirname
426     for(k = strlen(t) - 1; k >= 0; k--)
427     {
428       if (t[k] == '/')
429       {
430         log->log("JSONServer", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
431         dateDirName = new char[strlen(&t[k+1]) + 1];
432         strcpy(dateDirName, &t[k+1]);
433         break;
434       }
435     }
436
437     // Find the titledirname
438
439     for(j = k-1; j >= 0; j--)
440     {
441       if (t[j] == '/')
442       {
443         log->log("JSONServer", Log::DEBUG, "l2: %i", k - j);
444         titleDirName = new char[k - j];
445         memcpy(titleDirName, &t[j+1], k - j - 1);
446         titleDirName[k - j - 1] = '\0';
447         break;
448       }
449     }
450
451     // Find the foldername
452
453     log->log("JSONServer", Log::DEBUG, "j = %u, strlenvd = %u", j, strlen(VideoDirectory));
454     if (j > strlen(VideoDirectory)) // Rec is in a subfolder now
455     {
456       for(m = j-1; m >= 0; m--)
457       {
458         if (t[m] == '/')
459         {
460           log->log("JSONServer", Log::DEBUG, "l3: %i", j - m);
461           folderName = new char[j - m];
462           memcpy(folderName, &t[m+1], j - m - 1);
463           folderName[j - m - 1] = '\0';
464           break;
465         }
466       }
467     }
468
469     ExchangeChars(requestedNewPath, true);
470
471     log->log("JSONServer", Log::DEBUG, "datedirname: %s", dateDirName);
472     log->log("JSONServer", Log::DEBUG, "titledirname: %s", titleDirName);
473     log->log("JSONServer", Log::DEBUG, "viddir: %s", VideoDirectory);
474     if (folderName) log->log("JSONServer", Log::DEBUG, "folderName: %s", folderName);
475     log->log("JSONServer", Log::DEBUG, "EC: %s", requestedNewPath);
476
477     // Could be a new path - construct that first and test
478     newContainer = new char[strlen(VideoDirectory) + strlen(requestedNewPath) + strlen(titleDirName) + 1];
479     sprintf(newContainer, "%s%s", VideoDirectory, requestedNewPath);
480     log->log("JSONServer", Log::DEBUG, "NPT: %s", newContainer);
481     struct stat dstat;
482     int statret = stat(newContainer, &dstat);
483     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
484     {
485       log->log("JSONServer", Log::DEBUG, "new path does not exist (1)");
486       int mkdirret = mkdir(newContainer, 0755);
487       if (mkdirret != 0) throw 4;
488     }
489     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
490     {
491       // Something exists but it's not a dir
492       throw 5;
493     }
494
495     // New path now created or was there already
496
497     sprintf(newContainer, "%s%s%s", VideoDirectory, requestedNewPath, titleDirName);
498     log->log("JSONServer", Log::DEBUG, "%s", newContainer);
499
500     statret = stat(newContainer, &dstat);
501     if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
502     {
503       log->log("JSONServer", Log::DEBUG, "new dir does not exist (2)");
504       int mkdirret = mkdir(newContainer, 0755);
505       if (mkdirret != 0) throw 6;
506     }
507     else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR)))
508     {
509       // Something exists but it's not a dir
510       throw 7;
511     }
512
513     // Ok, the directory container has been made, or it pre-existed.
514
515     newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
516     sprintf(newDir, "%s/%s", newContainer, dateDirName);
517
518     log->log("JSONServer", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
519     if (rename(t, newDir) != 0) throw 8;
520     
521     // Success. Test for remove old dir containter
522     char* tempOldTitleDir = new char[k+1];
523     memcpy(tempOldTitleDir, t, k);
524     tempOldTitleDir[k] = '\0';
525     log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(tempOldTitleDir), tempOldTitleDir);
526     rmdir(tempOldTitleDir); // can't do anything about a fail result at this point.
527     delete[] tempOldTitleDir;
528
529     // Test for remove old foldername
530     if (folderName)
531     {
532       char* tempOldFolderName = new char[j+1];
533       memcpy(tempOldFolderName, t, j);
534       tempOldFolderName[j] = '\0';
535       log->log("JSONServer", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldfoldername: %s", j+1, j, strlen(tempOldFolderName), tempOldFolderName);
536       /*
537       DESCRIPTION
538       rmdir() deletes a directory, which must be empty.
539       ENOTEMPTY - pathname  contains  entries  other than . and ..
540       So, should be safe to call rmdir on non-empty dir
541       */
542       rmdir(tempOldFolderName); // can't do anything about a fail result at this point.
543       delete[] tempOldFolderName;
544     }
545
546     ::Recordings.Update();
547     js["Result"] = true;
548     js["NewRecordingFileName"] = newDir;
549   }
550   catch (int e)
551   {
552     js["Result"] = false;
553     if (e == 1)
554     {
555       log->log("JSONServer", Log::ERR, "Bad parameters");
556       js["Error"] = "Bad request parameters";
557     }
558     else if (e == 2)
559     {
560       log->log("JSONServer", Log::ERR, "Could not find recording to move");
561       js["Error"] = "Bad filename";
562     }
563     else if (e == 3)
564     {
565       log->log("JSONServer", Log::ERR, "Could not move recording, it is still recording");
566       js["Error"] = "Cannot move recording in progress";
567     }
568     else if (e == 4)
569     {
570       log->log("JSONServer", Log::ERR, "Failed to make new dir (1)");
571       js["Error"] = "Failed to create new directory (1)";
572     }
573     else if (e == 5)
574     {
575       log->log("JSONServer", Log::ERR, "Something already exists? (1)");
576       js["Error"] = "Something already exists at the new path (1)";
577     }
578     else if (e == 6)
579     {
580       log->log("JSONServer", Log::ERR, "Failed to make new dir (2)");
581       js["Error"] = "Failed to create new directory (2)";
582     }
583     else if (e == 7)
584     {
585       log->log("JSONServer", Log::ERR, "Something already exists?");
586       js["Error"] = "Something already exists at the new path";
587     }
588     else if (e == 8)
589     {
590       log->log("JSONServer", Log::ERR, "Rename failed");
591       js["Error"] = "Move failed";
592     }
593   }
594
595   if (fileNameToMove)   delete[] fileNameToMove;
596   if (requestedNewPath) delete[] requestedNewPath;
597   if (dateDirName)      delete[] dateDirName;
598   if (titleDirName)     delete[] titleDirName;
599   if (folderName)       delete[] folderName;
600   if (newContainer)     delete[] newContainer;
601   if (newDir)           delete[] newDir;
602
603   return true;
604 }
605
606 bool jsonserver_channellist(Json::Value& js)
607 {
608   Log* log = Log::getInstance();
609   log->log("JSONServer", Log::DEBUG, "channellist");
610
611   Json::Value jschannels;
612   
613   int type;
614   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
615   {
616     if (!channel->GroupSep())
617     {
618 //      log->log("JSONServer", Log::DEBUG, "name: '%s'", channel->Name());
619
620 //      if (channel->Vpid()) type = 1;
621 //      else if (channel->Apid(0)) type = 2;
622 //      else continue;
623
624       Json::Value oneChannel;
625       oneChannel["Number"] = channel->Number();
626 //      oneChannel["Type"] = type;
627       oneChannel["Name"] = channel->Name();
628 //#if VDRVERSNUM < 10703
629 //      oneChannel["VType"] = 2;
630 //#else
631 //      oneChannel["VType"] = channel->Vtype();
632 //#endif
633       jschannels.append(oneChannel);    
634     }
635   }
636   js["Channels"] = jschannels;
637   
638   return true;
639 }
640
641 bool jsonserver_channelschedule(Json::Value& js, const char* postData)
642 {
643   Log* log = Log::getInstance();
644   log->log("JSONServer", Log::DEBUG, "channelschedule '%s'", postData);
645
646   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);  
647   char sStartTime[15];      int mgv2 = mg_get_var(postData, strlen(postData), "starttime", sStartTime, 15);  
648   char sDuration[15];       int mgv3 = mg_get_var(postData, strlen(postData), "duration", sDuration, 15);  
649
650   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) )
651   {
652     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i", mgv1, mgv2, mgv3);
653     js["Result"] = false;
654     js["Error"] = "Bad request parameters";
655     return true;
656   }
657
658   int channelNumber = atoi(sChannelNumber);
659   int startTime = atoi(sStartTime); 
660   int duration = atoi(sDuration); 
661
662   cChannel* channel = NULL;
663   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
664   {
665     if (channel->GroupSep()) continue;
666     if (channel->Number() == channelNumber) break;
667   }
668
669   if (!channel)
670   {
671     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
672     js["Result"] = false;
673     js["Error"] = "Could not find channel";
674     return true;
675   }
676
677   cSchedulesLock MutexLock;
678   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
679   if (!Schedules)
680   {
681     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
682     js["Result"] = false;
683     js["Error"] = "Internal schedules error (1)";
684     return true;
685   }
686   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
687   if (!Schedule)     
688   {
689     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
690     js["Result"] = false;
691     js["Error"] = "Internal schedules error (2)";
692     return true;
693   }
694     
695   Json::Value jsevents;
696
697   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
698   {
699     //in the past filter
700     if ((event->StartTime() + event->Duration()) < time(NULL)) continue;
701    //start time filter
702     if ((event->StartTime() + event->Duration()) <= startTime) continue;
703     //duration filter
704     if (event->StartTime() >= (startTime + duration)) continue;
705
706     Json::Value oneEvent;
707     oneEvent["ID"] = event->EventID();
708     oneEvent["Time"] = (Json::UInt)event->StartTime();
709     oneEvent["Duration"] = event->Duration();
710     oneEvent["Title"] = event->Title() ? event->Title() : "";
711     oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
712     //oneEvent["Description"] = event->Description() ? event->Description() : "";
713     jsevents.append(oneEvent);
714   }
715
716   js["Result"] = true;
717   js["Events"] = jsevents;
718   return true;
719 }
720
721 bool jsonserver_getscheduleevent(Json::Value& js, const char* postData)
722 {
723   Log* log = Log::getInstance();
724   log->log("JSONServer", Log::DEBUG, "getscheduleevent '%s'", postData);
725   
726   char sChannelNumber[15];  int mgv1 = mg_get_var(postData, strlen(postData), "channelnumber", sChannelNumber, 15);
727   char sEventID[15];        int mgv2 = mg_get_var(postData, strlen(postData), "eventid", sEventID, 15);
728   
729   if ( (mgv1 == -1) || (mgv2 == -1) )
730   {
731     log->log("JSONServer", Log::ERR, "request mgvs: %i %i", mgv1, mgv2);
732     js["Result"] = false;
733     js["Error"] = "Bad request parameters";
734     return true;
735   }
736   
737   int channelNumber = atoi(sChannelNumber);
738   int eventID = atoi(sEventID);
739   
740   cChannel* channel = NULL;
741   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
742   {
743     if (channel->GroupSep()) continue;
744     if (channel->Number() == channelNumber) break;
745   }
746   
747   if (!channel)
748   {
749     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
750     js["Result"] = false;
751     js["Error"] = "Could not find channel";
752     return true;
753   }
754   
755   cSchedulesLock MutexLock;
756   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
757   if (!Schedules)
758   {
759     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
760     js["Result"] = false;
761     js["Error"] = "Internal schedules error (1)";
762     return true;
763   }
764   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
765   if (!Schedule)
766   {
767     log->log("JSONServer", Log::ERR, "Could not find requested channel: %i", channelNumber);
768     js["Result"] = false;
769     js["Error"] = "Internal schedules error (2)";
770     return true;
771   }
772   
773   cEvent* event = Schedule->GetEvent(eventID);
774   if (!event)
775   {
776     log->log("JSONServer", Log::ERR, "Could not find requested event: %i", eventID);
777     js["Result"] = false;
778     js["Error"] = "Internal schedules error (3)";
779     return true;
780   }
781   
782   Json::Value oneEvent;
783   oneEvent["ID"] = event->EventID();
784   oneEvent["Time"] = (Json::UInt)event->StartTime();
785   oneEvent["Duration"] = event->Duration();
786   oneEvent["Title"] = event->Title() ? event->Title() : "";
787   oneEvent["ShortText"] = event->ShortText() ? event->ShortText() : "";
788   oneEvent["Description"] = event->Description() ? event->Description() : "";
789   oneEvent["HasTimer"] = event->HasTimer();
790   oneEvent["RunningStatus"] = event->RunningStatus();
791
792   js["Result"] = true;
793   js["Event"] = oneEvent;
794   return true;
795 }
796
797 bool jsonserver_timerlist(Json::Value& js)
798 {
799   Log* log = Log::getInstance();
800   log->log("JSONServer", Log::DEBUG, "timerlist");
801
802   Json::Value jstimers;
803   
804   cTimer *timer;
805   int numTimers = Timers.Count();
806
807   for (int i = 0; i < numTimers; i++)
808   {
809     timer = Timers.Get(i);
810     Json::Value oneTimer;
811     oneTimer["Active"] = timer->HasFlags(tfActive);
812     oneTimer["Recording"] = timer->Recording();
813     oneTimer["Pending"] = timer->Pending();
814     oneTimer["Priority"] = timer->Priority();
815     oneTimer["Lifetime"] = timer->Lifetime();
816     oneTimer["ChannelNumber"] = timer->Channel()->Number();
817     oneTimer["StartTime"] = (int)timer->StartTime();
818     oneTimer["StopTime"] = (int)timer->StopTime();
819     oneTimer["Day"] = (int)timer->Day();
820     oneTimer["WeekDays"] = timer->WeekDays();
821     oneTimer["Name"] = timer->File();
822     jstimers.append(oneTimer);
823   }
824   
825   js["Timers"] = jstimers;
826   js["Result"] = true;
827   return true;
828 }
829
830 bool jsonserver_timerdel(Json::Value& js, const char* postData)
831 {
832   Log* log = Log::getInstance();
833   log->log("JSONServer", Log::DEBUG, "timerdel");
834
835   char sdelChannel[15];   int mgv1 = mg_get_var(postData, strlen(postData), "delchannel", sdelChannel, 15);  
836   char sdelWeekdays[15];  int mgv2 = mg_get_var(postData, strlen(postData), "delweekdays", sdelWeekdays, 15);  
837   char sdelDay[15];       int mgv3 = mg_get_var(postData, strlen(postData), "delday", sdelDay, 15);  
838   char sdelStart[15];     int mgv4 = mg_get_var(postData, strlen(postData), "delstart", sdelStart, 15);  
839   char sdelStop[15];      int mgv5 = mg_get_var(postData, strlen(postData), "delstop", sdelStop, 15);  
840
841   if ( (mgv1 == -1) || (mgv2 == -1) || (mgv3 == -1) || (mgv4 == -1) || (mgv5 == -1) )
842   {
843     log->log("JSONServer", Log::ERR, "request mgvs: %i %i %i %i %i", mgv1, mgv2, mgv3, mgv4, mgv5);
844     js["Result"] = false;
845     js["Error"] = "Bad request parameters";
846     return true;
847   }
848
849   int delChannel = atoi(sdelChannel); 
850   int delWeekdays = atoi(sdelWeekdays); 
851   int delDay = atoi(sdelDay); 
852   int delStart = atoi(sdelStart); 
853   int delStop = atoi(sdelStop); 
854
855   cTimer* ti = NULL;
856   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
857   {
858     if  ( (ti->Channel()->Number() == delChannel)
859      &&   ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
860      &&   (ti->StartTime() == delStart)
861      &&   (ti->StopTime() == delStop) )
862        break;
863   }
864   
865   if (!ti)
866   {
867     log->log("JSONServer", Log::ERR, "Could not find timer");
868     js["Result"] = false;
869     js["Error"] = "Could not find timer";
870     return true;
871   }
872
873   if (Timers.BeingEdited())
874   {
875     log->log("JSONServer", Log::ERR, "Unable to delete timer - timers being edited at VDR");
876     js["Result"] = false;
877     js["Error"] = "Timers being edited at VDR";
878     return true; 
879   }
880   
881   if (ti->Recording())
882   {
883     log->log("JSONServer", Log::ERR, "Unable to delete timer - timer is running");
884     js["Result"] = false;
885     js["Error"] = "Timer is running";
886     return true;
887   }
888   
889   Timers.Del(ti);
890   Timers.SetModified();
891   js["Result"] = true;
892     
893   return true;
894 }
895
896 bool jsonserver_timerset(Json::Value& js, const char* postData)
897 {
898   Log* log = Log::getInstance();
899   log->log("JSONServer", Log::DEBUG, "timerset");
900
901   char sTimerString[1024];   int mgv1 = mg_get_var(postData, strlen(postData), "timerstring", sTimerString, 1024);  
902
903   if (mgv1 == -1)
904   {
905     log->log("JSONServer", Log::ERR, "Could not get timerstring");
906     js["Result"] = false;
907     js["Error"] = "Bad request parameters";
908     return true;
909   }
910
911   log->log("JSONServer", Log::DEBUG, "'%s'", sTimerString);
912   cTimer *timer = new cTimer;
913   if (!timer->Parse(sTimerString))
914   {
915     delete timer;
916     js["Result"] = false;
917     js["Error"] = "Failed to parse timer request details";
918     return true;
919   }
920
921   cTimer *t = Timers.GetTimer(timer);
922   if (t)
923   {
924     delete timer;
925     js["Result"] = false;
926     js["Error"] = "Timer already exists";
927     return true;
928   }
929
930   Timers.Add(timer);
931   Timers.SetModified();
932   js["Result"] = true;
933   return true;
934 }
935